Completed
Push — master ( 5bf5a9...80b817 )
by Rain
01:36
created

$.widget(ꞌui.resizableꞌ)._create   F

Complexity

Conditions 12
Paths > 20000

Size

Total Lines 169

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
nc 110592
dl 0
loc 169
rs 2
c 0
b 0
f 0
nop 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like $.widget(ꞌui.resizableꞌ)._create often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*! jQuery UI - v1.10.3 - 2013-11-25
2
* http://jqueryui.com
3
* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.autocomplete.js, jquery.ui.menu.js
4
* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
5
6
(function( $, undefined ) {
7
8
var uuid = 0,
9
	runiqueId = /^ui-id-\d+$/;
10
11
// $.ui might exist from components with no dependencies, e.g., $.ui.position
12
$.ui = $.ui || {};
13
14
$.extend( $.ui, {
15
	version: "1.10.3",
16
17
	keyCode: {
18
		BACKSPACE: 8,
19
		COMMA: 188,
20
		DELETE: 46,
21
		DOWN: 40,
22
		END: 35,
23
		ENTER: 13,
24
		ESCAPE: 27,
25
		HOME: 36,
26
		LEFT: 37,
27
		NUMPAD_ADD: 107,
28
		NUMPAD_DECIMAL: 110,
29
		NUMPAD_DIVIDE: 111,
30
		NUMPAD_ENTER: 108,
31
		NUMPAD_MULTIPLY: 106,
32
		NUMPAD_SUBTRACT: 109,
33
		PAGE_DOWN: 34,
34
		PAGE_UP: 33,
35
		PERIOD: 190,
36
		RIGHT: 39,
37
		SPACE: 32,
38
		TAB: 9,
39
		UP: 38
40
	}
41
});
42
43
// plugins
44
$.fn.extend({
45
	focus: (function( orig ) {
46
		return function( delay, fn ) {
47
			return typeof delay === "number" ?
48
				this.each(function() {
49
					var elem = this;
50
					setTimeout(function() {
51
						$( elem ).focus();
52
						if ( fn ) {
53
							fn.call( elem );
54
						}
55
					}, delay );
56
				}) :
57
				orig.apply( this, arguments );
58
		};
59
	})( $.fn.focus ),
60
61
	scrollParent: function() {
62
		var scrollParent;
63
		if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) {
64
			scrollParent = this.parents().filter(function() {
65
				return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
66
			}).eq(0);
67
		} else {
68
			scrollParent = this.parents().filter(function() {
69
				return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));
70
			}).eq(0);
71
		}
72
73
		return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent;
74
	},
75
76
	zIndex: function( zIndex ) {
77
		if ( zIndex !== undefined ) {
78
			return this.css( "zIndex", zIndex );
79
		}
80
81
		if ( this.length ) {
82
			var elem = $( this[ 0 ] ), position, value;
83
			while ( elem.length && elem[ 0 ] !== document ) {
84
				// Ignore z-index if position is set to a value where z-index is ignored by the browser
85
				// This makes behavior of this function consistent across browsers
86
				// WebKit always returns auto if the element is positioned
87
				position = elem.css( "position" );
88
				if ( position === "absolute" || position === "relative" || position === "fixed" ) {
89
					// IE returns 0 when zIndex is not specified
90
					// other browsers return a string
91
					// we ignore the case of nested elements with an explicit value of 0
92
					// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
93
					value = parseInt( elem.css( "zIndex" ), 10 );
94
					if ( !isNaN( value ) && value !== 0 ) {
95
						return value;
96
					}
97
				}
98
				elem = elem.parent();
99
			}
100
		}
101
102
		return 0;
103
	},
104
105
	uniqueId: function() {
106
		return this.each(function() {
107
			if ( !this.id ) {
108
				this.id = "ui-id-" + (++uuid);
109
			}
110
		});
111
	},
112
113
	removeUniqueId: function() {
114
		return this.each(function() {
115
			if ( runiqueId.test( this.id ) ) {
116
				$( this ).removeAttr( "id" );
117
			}
118
		});
119
	}
120
});
121
122
// selectors
123
function focusable( element, isTabIndexNotNaN ) {
124
	var map, mapName, img,
125
		nodeName = element.nodeName.toLowerCase();
126
	if ( "area" === nodeName ) {
127
		map = element.parentNode;
128
		mapName = map.name;
129
		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
130
			return false;
131
		}
132
		img = $( "img[usemap=#" + mapName + "]" )[0];
133
		return !!img && visible( img );
134
	}
135
	return ( /input|select|textarea|button|object/.test( nodeName ) ?
136
		!element.disabled :
137
		"a" === nodeName ?
138
			element.href || isTabIndexNotNaN :
139
			isTabIndexNotNaN) &&
140
		// the element and all of its ancestors must be visible
141
		visible( element );
142
}
143
144
function visible( element ) {
145
	return $.expr.filters.visible( element ) &&
146
		!$( element ).parents().addBack().filter(function() {
147
			return $.css( this, "visibility" ) === "hidden";
148
		}).length;
149
}
150
151
$.extend( $.expr[ ":" ], {
152
	data: $.expr.createPseudo ?
153
		$.expr.createPseudo(function( dataName ) {
154
			return function( elem ) {
155
				return !!$.data( elem, dataName );
156
			};
157
		}) :
158
		// support: jQuery <1.8
159
		function( elem, i, match ) {
160
			return !!$.data( elem, match[ 3 ] );
161
		},
162
163
	focusable: function( element ) {
164
		return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
165
	},
166
167
	tabbable: function( element ) {
168
		var tabIndex = $.attr( element, "tabindex" ),
169
			isTabIndexNaN = isNaN( tabIndex );
170
		return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
171
	}
172
});
173
174
// support: jQuery <1.8
175
if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
176
	$.each( [ "Width", "Height" ], function( i, name ) {
177
		var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
178
			type = name.toLowerCase(),
179
			orig = {
180
				innerWidth: $.fn.innerWidth,
181
				innerHeight: $.fn.innerHeight,
182
				outerWidth: $.fn.outerWidth,
183
				outerHeight: $.fn.outerHeight
184
			};
185
186
		function reduce( elem, size, border, margin ) {
187
			$.each( side, function() {
188
				size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
189
				if ( border ) {
190
					size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
191
				}
192
				if ( margin ) {
193
					size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
194
				}
195
			});
196
			return size;
197
		}
198
199
		$.fn[ "inner" + name ] = function( size ) {
200
			if ( size === undefined ) {
201
				return orig[ "inner" + name ].call( this );
202
			}
203
204
			return this.each(function() {
205
				$( this ).css( type, reduce( this, size ) + "px" );
206
			});
207
		};
208
209
		$.fn[ "outer" + name] = function( size, margin ) {
210
			if ( typeof size !== "number" ) {
211
				return orig[ "outer" + name ].call( this, size );
212
			}
213
214
			return this.each(function() {
215
				$( this).css( type, reduce( this, size, true, margin ) + "px" );
216
			});
217
		};
218
	});
219
}
220
221
// support: jQuery <1.8
222
if ( !$.fn.addBack ) {
223
	$.fn.addBack = function( selector ) {
224
		return this.add( selector == null ?
225
			this.prevObject : this.prevObject.filter( selector )
226
		);
227
	};
228
}
229
230
// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
231
if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
232
	$.fn.removeData = (function( removeData ) {
233
		return function( key ) {
234
			if ( arguments.length ) {
235
				return removeData.call( this, $.camelCase( key ) );
236
			} else {
237
				return removeData.call( this );
238
			}
239
		};
240
	})( $.fn.removeData );
241
}
242
243
244
245
246
247
// deprecated
248
$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
249
250
$.support.selectstart = "onselectstart" in document.createElement( "div" );
251
$.fn.extend({
252
	disableSelection: function() {
253
		return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
254
			".ui-disableSelection", function( event ) {
255
				event.preventDefault();
256
			});
257
	},
258
259
	enableSelection: function() {
260
		return this.unbind( ".ui-disableSelection" );
261
	}
262
});
263
264
$.extend( $.ui, {
265
	// $.ui.plugin is deprecated. Use $.widget() extensions instead.
266
	plugin: {
267
		add: function( module, option, set ) {
268
			var i,
269
				proto = $.ui[ module ].prototype;
270
			for ( i in set ) {
271
				proto.plugins[ i ] = proto.plugins[ i ] || [];
272
				proto.plugins[ i ].push( [ option, set[ i ] ] );
273
			}
274
		},
275
		call: function( instance, name, args ) {
276
			var i,
277
				set = instance.plugins[ name ];
278
			if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) {
279
				return;
280
			}
281
282
			for ( i = 0; i < set.length; i++ ) {
283
				if ( instance.options[ set[ i ][ 0 ] ] ) {
284
					set[ i ][ 1 ].apply( instance.element, args );
285
				}
286
			}
287
		}
288
	},
289
290
	// only used by resizable
291
	hasScroll: function( el, a ) {
292
293
		//If overflow is hidden, the element might have extra content, but the user wants to hide it
294
		if ( $( el ).css( "overflow" ) === "hidden") {
295
			return false;
296
		}
297
298
		var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
299
			has = false;
300
301
		if ( el[ scroll ] > 0 ) {
302
			return true;
303
		}
304
305
		// TODO: determine which cases actually cause this to happen
306
		// if the element doesn't have the scroll set, see if it's possible to
307
		// set the scroll
308
		el[ scroll ] = 1;
309
		has = ( el[ scroll ] > 0 );
310
		el[ scroll ] = 0;
311
		return has;
312
	}
313
});
314
315
})( jQuery );
316
(function( $, undefined ) {
317
318
var uuid = 0,
319
	slice = Array.prototype.slice,
320
	_cleanData = $.cleanData;
321
$.cleanData = function( elems ) {
322
	for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
323
		try {
324
			$( elem ).triggerHandler( "remove" );
325
		// http://bugs.jquery.com/ticket/8235
326
		} catch( e ) {}
327
	}
328
	_cleanData( elems );
329
};
330
331
$.widget = function( name, base, prototype ) {
332
	var fullName, existingConstructor, constructor, basePrototype,
333
		// proxiedPrototype allows the provided prototype to remain unmodified
334
		// so that it can be used as a mixin for multiple widgets (#8876)
335
		proxiedPrototype = {},
336
		namespace = name.split( "." )[ 0 ];
337
338
	name = name.split( "." )[ 1 ];
339
	fullName = namespace + "-" + name;
340
341
	if ( !prototype ) {
342
		prototype = base;
343
		base = $.Widget;
344
	}
345
346
	// create selector for plugin
347
	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
348
		return !!$.data( elem, fullName );
349
	};
350
351
	$[ namespace ] = $[ namespace ] || {};
352
	existingConstructor = $[ namespace ][ name ];
353
	constructor = $[ namespace ][ name ] = function( options, element ) {
354
		// allow instantiation without "new" keyword
355
		if ( !this._createWidget ) {
356
			return new constructor( options, element );
357
		}
358
359
		// allow instantiation without initializing for simple inheritance
360
		// must use "new" keyword (the code above always passes args)
361
		if ( arguments.length ) {
362
			this._createWidget( options, element );
363
		}
364
	};
365
	// extend with the existing constructor to carry over any static properties
366
	$.extend( constructor, existingConstructor, {
367
		version: prototype.version,
368
		// copy the object used to create the prototype in case we need to
369
		// redefine the widget later
370
		_proto: $.extend( {}, prototype ),
371
		// track widgets that inherit from this widget in case this widget is
372
		// redefined after a widget inherits from it
373
		_childConstructors: []
374
	});
375
376
	basePrototype = new base();
377
	// we need to make the options hash a property directly on the new instance
378
	// otherwise we'll modify the options hash on the prototype that we're
379
	// inheriting from
380
	basePrototype.options = $.widget.extend( {}, basePrototype.options );
381
	$.each( prototype, function( prop, value ) {
382
		if ( !$.isFunction( value ) ) {
383
			proxiedPrototype[ prop ] = value;
384
			return;
385
		}
386
		proxiedPrototype[ prop ] = (function() {
387
			var _super = function() {
388
					return base.prototype[ prop ].apply( this, arguments );
389
				},
390
				_superApply = function( args ) {
391
					return base.prototype[ prop ].apply( this, args );
392
				};
393
			return function() {
394
				var __super = this._super,
395
					__superApply = this._superApply,
396
					returnValue;
397
398
				this._super = _super;
399
				this._superApply = _superApply;
400
401
				returnValue = value.apply( this, arguments );
402
403
				this._super = __super;
404
				this._superApply = __superApply;
405
406
				return returnValue;
407
			};
408
		})();
409
	});
410
	constructor.prototype = $.widget.extend( basePrototype, {
411
		// TODO: remove support for widgetEventPrefix
412
		// always use the name + a colon as the prefix, e.g., draggable:start
413
		// don't prefix for widgets that aren't DOM-based
414
		widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
415
	}, proxiedPrototype, {
416
		constructor: constructor,
417
		namespace: namespace,
418
		widgetName: name,
419
		widgetFullName: fullName
420
	});
421
422
	// If this widget is being redefined then we need to find all widgets that
423
	// are inheriting from it and redefine all of them so that they inherit from
424
	// the new version of this widget. We're essentially trying to replace one
425
	// level in the prototype chain.
426
	if ( existingConstructor ) {
427
		$.each( existingConstructor._childConstructors, function( i, child ) {
428
			var childPrototype = child.prototype;
429
430
			// redefine the child widget using the same prototype that was
431
			// originally used, but inherit from the new version of the base
432
			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
433
		});
434
		// remove the list of existing child constructors from the old constructor
435
		// so the old child constructors can be garbage collected
436
		delete existingConstructor._childConstructors;
437
	} else {
438
		base._childConstructors.push( constructor );
439
	}
440
441
	$.widget.bridge( name, constructor );
442
};
443
444
$.widget.extend = function( target ) {
445
	var input = slice.call( arguments, 1 ),
446
		inputIndex = 0,
447
		inputLength = input.length,
448
		key,
449
		value;
450
	for ( ; inputIndex < inputLength; inputIndex++ ) {
451
		for ( key in input[ inputIndex ] ) {
452
			value = input[ inputIndex ][ key ];
453
			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
454
				// Clone objects
455
				if ( $.isPlainObject( value ) ) {
456
					target[ key ] = $.isPlainObject( target[ key ] ) ?
457
						$.widget.extend( {}, target[ key ], value ) :
458
						// Don't extend strings, arrays, etc. with objects
459
						$.widget.extend( {}, value );
460
				// Copy everything else by reference
461
				} else {
462
					target[ key ] = value;
463
				}
464
			}
465
		}
466
	}
467
	return target;
468
};
469
470
$.widget.bridge = function( name, object ) {
471
	var fullName = object.prototype.widgetFullName || name;
472
	$.fn[ name ] = function( options ) {
473
		var isMethodCall = typeof options === "string",
474
			args = slice.call( arguments, 1 ),
475
			returnValue = this;
476
477
		// allow multiple hashes to be passed on init
478
		options = !isMethodCall && args.length ?
479
			$.widget.extend.apply( null, [ options ].concat(args) ) :
480
			options;
481
482
		if ( isMethodCall ) {
483
			this.each(function() {
484
				var methodValue,
485
					instance = $.data( this, fullName );
486
				if ( !instance ) {
487
					return $.error( "cannot call methods on " + name + " prior to initialization; " +
488
						"attempted to call method '" + options + "'" );
489
				}
490
				if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
491
					return $.error( "no such method '" + options + "' for " + name + " widget instance" );
492
				}
493
				methodValue = instance[ options ].apply( instance, args );
494
				if ( methodValue !== instance && methodValue !== undefined ) {
495
					returnValue = methodValue && methodValue.jquery ?
496
						returnValue.pushStack( methodValue.get() ) :
497
						methodValue;
498
					return false;
499
				}
500
			});
501
		} else {
502
			this.each(function() {
503
				var instance = $.data( this, fullName );
504
				if ( instance ) {
505
					instance.option( options || {} )._init();
506
				} else {
507
					$.data( this, fullName, new object( options, this ) );
508
				}
509
			});
510
		}
511
512
		return returnValue;
513
	};
514
};
515
516
$.Widget = function( /* options, element */ ) {};
517
$.Widget._childConstructors = [];
518
519
$.Widget.prototype = {
520
	widgetName: "widget",
521
	widgetEventPrefix: "",
522
	defaultElement: "<div>",
523
	options: {
524
		disabled: false,
525
526
		// callbacks
527
		create: null
528
	},
529
	_createWidget: function( options, element ) {
530
		element = $( element || this.defaultElement || this )[ 0 ];
531
		this.element = $( element );
532
		this.uuid = uuid++;
533
		this.eventNamespace = "." + this.widgetName + this.uuid;
534
		this.options = $.widget.extend( {},
535
			this.options,
536
			this._getCreateOptions(),
537
			options );
538
539
		this.bindings = $();
540
		this.hoverable = $();
541
		this.focusable = $();
542
543
		if ( element !== this ) {
544
			$.data( element, this.widgetFullName, this );
545
			this._on( true, this.element, {
546
				remove: function( event ) {
547
					if ( event.target === element ) {
548
						this.destroy();
549
					}
550
				}
551
			});
552
			this.document = $( element.style ?
553
				// element within the document
554
				element.ownerDocument :
555
				// element is window or document
556
				element.document || element );
557
			this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
558
		}
559
560
		this._create();
561
		this._trigger( "create", null, this._getCreateEventData() );
562
		this._init();
563
	},
564
	_getCreateOptions: $.noop,
565
	_getCreateEventData: $.noop,
566
	_create: $.noop,
567
	_init: $.noop,
568
569
	destroy: function() {
570
		this._destroy();
571
		// we can probably remove the unbind calls in 2.0
572
		// all event bindings should go through this._on()
573
		this.element
574
			.unbind( this.eventNamespace )
575
			// 1.9 BC for #7810
576
			// TODO remove dual storage
577
			.removeData( this.widgetName )
578
			.removeData( this.widgetFullName )
579
			// support: jquery <1.6.3
580
			// http://bugs.jquery.com/ticket/9413
581
			.removeData( $.camelCase( this.widgetFullName ) );
582
		this.widget()
583
			.unbind( this.eventNamespace )
584
			.removeAttr( "aria-disabled" )
585
			.removeClass(
586
				this.widgetFullName + "-disabled " +
587
				"ui-state-disabled" );
588
589
		// clean up events and states
590
		this.bindings.unbind( this.eventNamespace );
591
		this.hoverable.removeClass( "ui-state-hover" );
592
		this.focusable.removeClass( "ui-state-focus" );
593
	},
594
	_destroy: $.noop,
595
596
	widget: function() {
597
		return this.element;
598
	},
599
600
	option: function( key, value ) {
601
		var options = key,
602
			parts,
603
			curOption,
604
			i;
605
606
		if ( arguments.length === 0 ) {
607
			// don't return a reference to the internal hash
608
			return $.widget.extend( {}, this.options );
609
		}
610
611
		if ( typeof key === "string" ) {
612
			// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
613
			options = {};
614
			parts = key.split( "." );
615
			key = parts.shift();
616
			if ( parts.length ) {
617
				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
618
				for ( i = 0; i < parts.length - 1; i++ ) {
619
					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
620
					curOption = curOption[ parts[ i ] ];
621
				}
622
				key = parts.pop();
623
				if ( value === undefined ) {
624
					return curOption[ key ] === undefined ? null : curOption[ key ];
625
				}
626
				curOption[ key ] = value;
627
			} else {
628
				if ( value === undefined ) {
629
					return this.options[ key ] === undefined ? null : this.options[ key ];
630
				}
631
				options[ key ] = value;
632
			}
633
		}
634
635
		this._setOptions( options );
636
637
		return this;
638
	},
639
	_setOptions: function( options ) {
640
		var key;
641
642
		for ( key in options ) {
643
			this._setOption( key, options[ key ] );
644
		}
645
646
		return this;
647
	},
648
	_setOption: function( key, value ) {
649
		this.options[ key ] = value;
650
651
		if ( key === "disabled" ) {
652
			this.widget()
653
				.toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
654
				.attr( "aria-disabled", value );
655
			this.hoverable.removeClass( "ui-state-hover" );
656
			this.focusable.removeClass( "ui-state-focus" );
657
		}
658
659
		return this;
660
	},
661
662
	enable: function() {
663
		return this._setOption( "disabled", false );
664
	},
665
	disable: function() {
666
		return this._setOption( "disabled", true );
667
	},
668
669
	_on: function( suppressDisabledCheck, element, handlers ) {
670
		var delegateElement,
671
			instance = this;
672
673
		// no suppressDisabledCheck flag, shuffle arguments
674
		if ( typeof suppressDisabledCheck !== "boolean" ) {
675
			handlers = element;
676
			element = suppressDisabledCheck;
677
			suppressDisabledCheck = false;
678
		}
679
680
		// no element argument, shuffle and use this.element
681
		if ( !handlers ) {
682
			handlers = element;
683
			element = this.element;
684
			delegateElement = this.widget();
685
		} else {
686
			// accept selectors, DOM elements
687
			element = delegateElement = $( element );
688
			this.bindings = this.bindings.add( element );
689
		}
690
691
		$.each( handlers, function( event, handler ) {
692
			function handlerProxy() {
693
				// allow widgets to customize the disabled handling
694
				// - disabled as an array instead of boolean
695
				// - disabled class as method for disabling individual parts
696
				if ( !suppressDisabledCheck &&
697
						( instance.options.disabled === true ||
698
							$( this ).hasClass( "ui-state-disabled" ) ) ) {
699
					return;
700
				}
701
				return ( typeof handler === "string" ? instance[ handler ] : handler )
702
					.apply( instance, arguments );
703
			}
704
705
			// copy the guid so direct unbinding works
706
			if ( typeof handler !== "string" ) {
707
				handlerProxy.guid = handler.guid =
708
					handler.guid || handlerProxy.guid || $.guid++;
709
			}
710
711
			var match = event.match( /^(\w+)\s*(.*)$/ ),
712
				eventName = match[1] + instance.eventNamespace,
713
				selector = match[2];
714
			if ( selector ) {
715
				delegateElement.delegate( selector, eventName, handlerProxy );
716
			} else {
717
				element.bind( eventName, handlerProxy );
718
			}
719
		});
720
	},
721
722
	_off: function( element, eventName ) {
723
		eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
724
		element.unbind( eventName ).undelegate( eventName );
725
	},
726
727
	_delay: function( handler, delay ) {
728
		function handlerProxy() {
729
			return ( typeof handler === "string" ? instance[ handler ] : handler )
730
				.apply( instance, arguments );
731
		}
732
		var instance = this;
733
		return setTimeout( handlerProxy, delay || 0 );
734
	},
735
736
	_hoverable: function( element ) {
737
		this.hoverable = this.hoverable.add( element );
738
		this._on( element, {
739
			mouseenter: function( event ) {
740
				$( event.currentTarget ).addClass( "ui-state-hover" );
741
			},
742
			mouseleave: function( event ) {
743
				$( event.currentTarget ).removeClass( "ui-state-hover" );
744
			}
745
		});
746
	},
747
748
	_focusable: function( element ) {
749
		this.focusable = this.focusable.add( element );
750
		this._on( element, {
751
			focusin: function( event ) {
752
				$( event.currentTarget ).addClass( "ui-state-focus" );
753
			},
754
			focusout: function( event ) {
755
				$( event.currentTarget ).removeClass( "ui-state-focus" );
756
			}
757
		});
758
	},
759
760
	_trigger: function( type, event, data ) {
761
		var prop, orig,
762
			callback = this.options[ type ];
763
764
		data = data || {};
765
		event = $.Event( event );
766
		event.type = ( type === this.widgetEventPrefix ?
767
			type :
768
			this.widgetEventPrefix + type ).toLowerCase();
769
		// the original event may come from any element
770
		// so we need to reset the target on the new event
771
		event.target = this.element[ 0 ];
772
773
		// copy original event properties over to the new event
774
		orig = event.originalEvent;
775
		if ( orig ) {
776
			for ( prop in orig ) {
777
				if ( !( prop in event ) ) {
778
					event[ prop ] = orig[ prop ];
779
				}
780
			}
781
		}
782
783
		this.element.trigger( event, data );
784
		return !( $.isFunction( callback ) &&
785
			callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
786
			event.isDefaultPrevented() );
787
	}
788
};
789
790
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
791
	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
792
		if ( typeof options === "string" ) {
793
			options = { effect: options };
794
		}
795
		var hasOptions,
796
			effectName = !options ?
797
				method :
798
				options === true || typeof options === "number" ?
799
					defaultEffect :
800
					options.effect || defaultEffect;
801
		options = options || {};
802
		if ( typeof options === "number" ) {
803
			options = { duration: options };
804
		}
805
		hasOptions = !$.isEmptyObject( options );
806
		options.complete = callback;
807
		if ( options.delay ) {
808
			element.delay( options.delay );
809
		}
810
		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
811
			element[ method ]( options );
812
		} else if ( effectName !== method && element[ effectName ] ) {
813
			element[ effectName ]( options.duration, options.easing, callback );
814
		} else {
815
			element.queue(function( next ) {
816
				$( this )[ method ]();
817
				if ( callback ) {
818
					callback.call( element[ 0 ] );
819
				}
820
				next();
821
			});
822
		}
823
	};
824
});
825
826
})( jQuery );
827
(function( $, undefined ) {
828
829
var mouseHandled = false;
830
$( document ).mouseup( function() {
831
	mouseHandled = false;
832
});
833
834
$.widget("ui.mouse", {
835
	version: "1.10.3",
836
	options: {
837
		cancel: "input,textarea,button,select,option",
838
		distance: 1,
839
		delay: 0
840
	},
841
	_mouseInit: function() {
842
		var that = this;
843
844
		this.element
845
			.bind("mousedown."+this.widgetName, function(event) {
846
				return that._mouseDown(event);
847
			})
848
			.bind("click."+this.widgetName, function(event) {
849
				if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
850
					$.removeData(event.target, that.widgetName + ".preventClickEvent");
851
					event.stopImmediatePropagation();
852
					return false;
853
				}
854
			});
855
856
		this.started = false;
857
	},
858
859
	// TODO: make sure destroying one instance of mouse doesn't mess with
860
	// other instances of mouse
861
	_mouseDestroy: function() {
862
		this.element.unbind("."+this.widgetName);
863
		if ( this._mouseMoveDelegate ) {
864
			$(document)
865
				.unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
866
				.unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
867
		}
868
	},
869
870
	_mouseDown: function(event) {
871
		// don't let more than one widget handle mouseStart
872
		if( mouseHandled ) { return; }
873
874
		// we may have missed mouseup (out of window)
875
		(this._mouseStarted && this._mouseUp(event));
876
877
		this._mouseDownEvent = event;
878
879
		var that = this,
880
			btnIsLeft = (event.which === 1),
881
			// event.target.nodeName works around a bug in IE 8 with
882
			// disabled inputs (#7620)
883
			elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
884
		if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
885
			return true;
886
		}
887
888
		this.mouseDelayMet = !this.options.delay;
889
		if (!this.mouseDelayMet) {
890
			this._mouseDelayTimer = setTimeout(function() {
891
				that.mouseDelayMet = true;
892
			}, this.options.delay);
893
		}
894
895
		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
896
			this._mouseStarted = (this._mouseStart(event) !== false);
897
			if (!this._mouseStarted) {
898
				event.preventDefault();
899
				return true;
900
			}
901
		}
902
903
		// Click event may never have fired (Gecko & Opera)
904
		if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
905
			$.removeData(event.target, this.widgetName + ".preventClickEvent");
906
		}
907
908
		// these delegates are required to keep context
909
		this._mouseMoveDelegate = function(event) {
910
			return that._mouseMove(event);
911
		};
912
		this._mouseUpDelegate = function(event) {
913
			return that._mouseUp(event);
914
		};
915
		$(document)
916
			.bind("mousemove."+this.widgetName, this._mouseMoveDelegate)
917
			.bind("mouseup."+this.widgetName, this._mouseUpDelegate);
918
919
		event.preventDefault();
920
921
		mouseHandled = true;
922
		return true;
923
	},
924
925
	_mouseMove: function(event) {
926
		// IE mouseup check - mouseup happened when mouse was out of window
927
		if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
928
			return this._mouseUp(event);
929
		}
930
931
		if (this._mouseStarted) {
932
			this._mouseDrag(event);
933
			return event.preventDefault();
934
		}
935
936
		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
937
			this._mouseStarted =
938
				(this._mouseStart(this._mouseDownEvent, event) !== false);
939
			(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
940
		}
941
942
		return !this._mouseStarted;
943
	},
944
945
	_mouseUp: function(event) {
946
		$(document)
947
			.unbind("mousemove."+this.widgetName, this._mouseMoveDelegate)
948
			.unbind("mouseup."+this.widgetName, this._mouseUpDelegate);
949
950
		if (this._mouseStarted) {
951
			this._mouseStarted = false;
952
953
			if (event.target === this._mouseDownEvent.target) {
954
				$.data(event.target, this.widgetName + ".preventClickEvent", true);
955
			}
956
957
			this._mouseStop(event);
958
		}
959
960
		return false;
961
	},
962
963
	_mouseDistanceMet: function(event) {
964
		return (Math.max(
965
				Math.abs(this._mouseDownEvent.pageX - event.pageX),
966
				Math.abs(this._mouseDownEvent.pageY - event.pageY)
967
			) >= this.options.distance
968
		);
969
	},
970
971
	_mouseDelayMet: function(/* event */) {
972
		return this.mouseDelayMet;
973
	},
974
975
	// These are placeholder methods, to be overriden by extending plugin
976
	_mouseStart: function(/* event */) {},
977
	_mouseDrag: function(/* event */) {},
978
	_mouseStop: function(/* event */) {},
979
	_mouseCapture: function(/* event */) { return true; }
980
});
981
982
})(jQuery);
983
(function( $, undefined ) {
984
985
$.ui = $.ui || {};
986
987
var cachedScrollbarWidth,
988
	max = Math.max,
989
	abs = Math.abs,
990
	round = Math.round,
991
	rhorizontal = /left|center|right/,
992
	rvertical = /top|center|bottom/,
993
	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
994
	rposition = /^\w+/,
995
	rpercent = /%$/,
996
	_position = $.fn.position;
997
998
function getOffsets( offsets, width, height ) {
999
	return [
1000
		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
1001
		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
1002
	];
1003
}
1004
1005
function parseCss( element, property ) {
1006
	return parseInt( $.css( element, property ), 10 ) || 0;
1007
}
1008
1009
function getDimensions( elem ) {
1010
	var raw = elem[0];
1011
	if ( raw.nodeType === 9 ) {
1012
		return {
1013
			width: elem.width(),
1014
			height: elem.height(),
1015
			offset: { top: 0, left: 0 }
1016
		};
1017
	}
1018
	if ( $.isWindow( raw ) ) {
1019
		return {
1020
			width: elem.width(),
1021
			height: elem.height(),
1022
			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
1023
		};
1024
	}
1025
	if ( raw.preventDefault ) {
1026
		return {
1027
			width: 0,
1028
			height: 0,
1029
			offset: { top: raw.pageY, left: raw.pageX }
1030
		};
1031
	}
1032
	return {
1033
		width: elem.outerWidth(),
1034
		height: elem.outerHeight(),
1035
		offset: elem.offset()
1036
	};
1037
}
1038
1039
$.position = {
1040
	scrollbarWidth: function() {
1041
		if ( cachedScrollbarWidth !== undefined ) {
1042
			return cachedScrollbarWidth;
1043
		}
1044
		var w1, w2,
1045
			div = $( "<div style='display:block;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
1046
			innerDiv = div.children()[0];
1047
1048
		$( "body" ).append( div );
1049
		w1 = innerDiv.offsetWidth;
1050
		div.css( "overflow", "scroll" );
1051
1052
		w2 = innerDiv.offsetWidth;
1053
1054
		if ( w1 === w2 ) {
1055
			w2 = div[0].clientWidth;
1056
		}
1057
1058
		div.remove();
1059
1060
		return (cachedScrollbarWidth = w1 - w2);
1061
	},
1062
	getScrollInfo: function( within ) {
1063
		var overflowX = within.isWindow ? "" : within.element.css( "overflow-x" ),
1064
			overflowY = within.isWindow ? "" : within.element.css( "overflow-y" ),
1065
			hasOverflowX = overflowX === "scroll" ||
1066
				( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
1067
			hasOverflowY = overflowY === "scroll" ||
1068
				( overflowY === "auto" && within.height < within.element[0].scrollHeight );
1069
		return {
1070
			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
1071
			height: hasOverflowX ? $.position.scrollbarWidth() : 0
1072
		};
1073
	},
1074
	getWithinInfo: function( element ) {
1075
		var withinElement = $( element || window ),
1076
			isWindow = $.isWindow( withinElement[0] );
1077
		return {
1078
			element: withinElement,
1079
			isWindow: isWindow,
1080
			offset: withinElement.offset() || { left: 0, top: 0 },
1081
			scrollLeft: withinElement.scrollLeft(),
1082
			scrollTop: withinElement.scrollTop(),
1083
			width: isWindow ? withinElement.width() : withinElement.outerWidth(),
1084
			height: isWindow ? withinElement.height() : withinElement.outerHeight()
1085
		};
1086
	}
1087
};
1088
1089
$.fn.position = function( options ) {
1090
	if ( !options || !options.of ) {
1091
		return _position.apply( this, arguments );
1092
	}
1093
1094
	// make a copy, we don't want to modify arguments
1095
	options = $.extend( {}, options );
1096
1097
	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
1098
		target = $( options.of ),
1099
		within = $.position.getWithinInfo( options.within ),
1100
		scrollInfo = $.position.getScrollInfo( within ),
1101
		collision = ( options.collision || "flip" ).split( " " ),
1102
		offsets = {};
1103
1104
	dimensions = getDimensions( target );
1105
	if ( target[0].preventDefault ) {
1106
		// force left top to allow flipping
1107
		options.at = "left top";
1108
	}
1109
	targetWidth = dimensions.width;
1110
	targetHeight = dimensions.height;
1111
	targetOffset = dimensions.offset;
1112
	// clone to reuse original targetOffset later
1113
	basePosition = $.extend( {}, targetOffset );
1114
1115
	// force my and at to have valid horizontal and vertical positions
1116
	// if a value is missing or invalid, it will be converted to center
1117
	$.each( [ "my", "at" ], function() {
1118
		var pos = ( options[ this ] || "" ).split( " " ),
1119
			horizontalOffset,
1120
			verticalOffset;
1121
1122
		if ( pos.length === 1) {
1123
			pos = rhorizontal.test( pos[ 0 ] ) ?
1124
				pos.concat( [ "center" ] ) :
1125
				rvertical.test( pos[ 0 ] ) ?
1126
					[ "center" ].concat( pos ) :
1127
					[ "center", "center" ];
1128
		}
1129
		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
1130
		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
1131
1132
		// calculate offsets
1133
		horizontalOffset = roffset.exec( pos[ 0 ] );
1134
		verticalOffset = roffset.exec( pos[ 1 ] );
1135
		offsets[ this ] = [
1136
			horizontalOffset ? horizontalOffset[ 0 ] : 0,
1137
			verticalOffset ? verticalOffset[ 0 ] : 0
1138
		];
1139
1140
		// reduce to just the positions without the offsets
1141
		options[ this ] = [
1142
			rposition.exec( pos[ 0 ] )[ 0 ],
1143
			rposition.exec( pos[ 1 ] )[ 0 ]
1144
		];
1145
	});
1146
1147
	// normalize collision option
1148
	if ( collision.length === 1 ) {
1149
		collision[ 1 ] = collision[ 0 ];
1150
	}
1151
1152
	if ( options.at[ 0 ] === "right" ) {
1153
		basePosition.left += targetWidth;
1154
	} else if ( options.at[ 0 ] === "center" ) {
1155
		basePosition.left += targetWidth / 2;
1156
	}
1157
1158
	if ( options.at[ 1 ] === "bottom" ) {
1159
		basePosition.top += targetHeight;
1160
	} else if ( options.at[ 1 ] === "center" ) {
1161
		basePosition.top += targetHeight / 2;
1162
	}
1163
1164
	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
1165
	basePosition.left += atOffset[ 0 ];
1166
	basePosition.top += atOffset[ 1 ];
1167
1168
	return this.each(function() {
1169
		var collisionPosition, using,
1170
			elem = $( this ),
1171
			elemWidth = elem.outerWidth(),
1172
			elemHeight = elem.outerHeight(),
1173
			marginLeft = parseCss( this, "marginLeft" ),
1174
			marginTop = parseCss( this, "marginTop" ),
1175
			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
1176
			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
1177
			position = $.extend( {}, basePosition ),
1178
			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
1179
1180
		if ( options.my[ 0 ] === "right" ) {
1181
			position.left -= elemWidth;
1182
		} else if ( options.my[ 0 ] === "center" ) {
1183
			position.left -= elemWidth / 2;
1184
		}
1185
1186
		if ( options.my[ 1 ] === "bottom" ) {
1187
			position.top -= elemHeight;
1188
		} else if ( options.my[ 1 ] === "center" ) {
1189
			position.top -= elemHeight / 2;
1190
		}
1191
1192
		position.left += myOffset[ 0 ];
1193
		position.top += myOffset[ 1 ];
1194
1195
		// if the browser doesn't support fractions, then round for consistent results
1196
		if ( !$.support.offsetFractions ) {
1197
			position.left = round( position.left );
1198
			position.top = round( position.top );
1199
		}
1200
1201
		collisionPosition = {
1202
			marginLeft: marginLeft,
1203
			marginTop: marginTop
1204
		};
1205
1206
		$.each( [ "left", "top" ], function( i, dir ) {
1207
			if ( $.ui.position[ collision[ i ] ] ) {
1208
				$.ui.position[ collision[ i ] ][ dir ]( position, {
1209
					targetWidth: targetWidth,
1210
					targetHeight: targetHeight,
1211
					elemWidth: elemWidth,
1212
					elemHeight: elemHeight,
1213
					collisionPosition: collisionPosition,
1214
					collisionWidth: collisionWidth,
1215
					collisionHeight: collisionHeight,
1216
					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
1217
					my: options.my,
1218
					at: options.at,
1219
					within: within,
1220
					elem : elem
1221
				});
1222
			}
1223
		});
1224
1225
		if ( options.using ) {
1226
			// adds feedback as second argument to using callback, if present
1227
			using = function( props ) {
1228
				var left = targetOffset.left - position.left,
1229
					right = left + targetWidth - elemWidth,
1230
					top = targetOffset.top - position.top,
1231
					bottom = top + targetHeight - elemHeight,
1232
					feedback = {
1233
						target: {
1234
							element: target,
1235
							left: targetOffset.left,
1236
							top: targetOffset.top,
1237
							width: targetWidth,
1238
							height: targetHeight
1239
						},
1240
						element: {
1241
							element: elem,
1242
							left: position.left,
1243
							top: position.top,
1244
							width: elemWidth,
1245
							height: elemHeight
1246
						},
1247
						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
1248
						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
1249
					};
1250
				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
1251
					feedback.horizontal = "center";
1252
				}
1253
				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
1254
					feedback.vertical = "middle";
1255
				}
1256
				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
1257
					feedback.important = "horizontal";
1258
				} else {
1259
					feedback.important = "vertical";
1260
				}
1261
				options.using.call( this, props, feedback );
1262
			};
1263
		}
1264
1265
		elem.offset( $.extend( position, { using: using } ) );
1266
	});
1267
};
1268
1269
$.ui.position = {
1270
	fit: {
1271
		left: function( position, data ) {
1272
			var within = data.within,
1273
				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
1274
				outerWidth = within.width,
1275
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1276
				overLeft = withinOffset - collisionPosLeft,
1277
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
1278
				newOverRight;
1279
1280
			// element is wider than within
1281
			if ( data.collisionWidth > outerWidth ) {
1282
				// element is initially over the left side of within
1283
				if ( overLeft > 0 && overRight <= 0 ) {
1284
					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
1285
					position.left += overLeft - newOverRight;
1286
				// element is initially over right side of within
1287
				} else if ( overRight > 0 && overLeft <= 0 ) {
1288
					position.left = withinOffset;
1289
				// element is initially over both left and right sides of within
1290
				} else {
1291
					if ( overLeft > overRight ) {
1292
						position.left = withinOffset + outerWidth - data.collisionWidth;
1293
					} else {
1294
						position.left = withinOffset;
1295
					}
1296
				}
1297
			// too far left -> align with left edge
1298
			} else if ( overLeft > 0 ) {
1299
				position.left += overLeft;
1300
			// too far right -> align with right edge
1301
			} else if ( overRight > 0 ) {
1302
				position.left -= overRight;
1303
			// adjust based on position and margin
1304
			} else {
1305
				position.left = max( position.left - collisionPosLeft, position.left );
1306
			}
1307
		},
1308
		top: function( position, data ) {
1309
			var within = data.within,
1310
				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
1311
				outerHeight = data.within.height,
1312
				collisionPosTop = position.top - data.collisionPosition.marginTop,
1313
				overTop = withinOffset - collisionPosTop,
1314
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
1315
				newOverBottom;
1316
1317
			// element is taller than within
1318
			if ( data.collisionHeight > outerHeight ) {
1319
				// element is initially over the top of within
1320
				if ( overTop > 0 && overBottom <= 0 ) {
1321
					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
1322
					position.top += overTop - newOverBottom;
1323
				// element is initially over bottom of within
1324
				} else if ( overBottom > 0 && overTop <= 0 ) {
1325
					position.top = withinOffset;
1326
				// element is initially over both top and bottom of within
1327
				} else {
1328
					if ( overTop > overBottom ) {
1329
						position.top = withinOffset + outerHeight - data.collisionHeight;
1330
					} else {
1331
						position.top = withinOffset;
1332
					}
1333
				}
1334
			// too far up -> align with top
1335
			} else if ( overTop > 0 ) {
1336
				position.top += overTop;
1337
			// too far down -> align with bottom edge
1338
			} else if ( overBottom > 0 ) {
1339
				position.top -= overBottom;
1340
			// adjust based on position and margin
1341
			} else {
1342
				position.top = max( position.top - collisionPosTop, position.top );
1343
			}
1344
		}
1345
	},
1346
	flip: {
1347
		left: function( position, data ) {
1348
			var within = data.within,
1349
				withinOffset = within.offset.left + within.scrollLeft,
1350
				outerWidth = within.width,
1351
				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
1352
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
1353
				overLeft = collisionPosLeft - offsetLeft,
1354
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
1355
				myOffset = data.my[ 0 ] === "left" ?
1356
					-data.elemWidth :
1357
					data.my[ 0 ] === "right" ?
1358
						data.elemWidth :
1359
						0,
1360
				atOffset = data.at[ 0 ] === "left" ?
1361
					data.targetWidth :
1362
					data.at[ 0 ] === "right" ?
1363
						-data.targetWidth :
1364
						0,
1365
				offset = -2 * data.offset[ 0 ],
1366
				newOverRight,
1367
				newOverLeft;
1368
1369
			if ( overLeft < 0 ) {
1370
				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
1371
				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
1372
					position.left += myOffset + atOffset + offset;
1373
				}
1374
			}
1375
			else if ( overRight > 0 ) {
1376
				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
1377
				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
1378
					position.left += myOffset + atOffset + offset;
1379
				}
1380
			}
1381
		},
1382
		top: function( position, data ) {
1383
			var within = data.within,
1384
				withinOffset = within.offset.top + within.scrollTop,
1385
				outerHeight = within.height,
1386
				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
1387
				collisionPosTop = position.top - data.collisionPosition.marginTop,
1388
				overTop = collisionPosTop - offsetTop,
1389
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
1390
				top = data.my[ 1 ] === "top",
1391
				myOffset = top ?
1392
					-data.elemHeight :
1393
					data.my[ 1 ] === "bottom" ?
1394
						data.elemHeight :
1395
						0,
1396
				atOffset = data.at[ 1 ] === "top" ?
1397
					data.targetHeight :
1398
					data.at[ 1 ] === "bottom" ?
1399
						-data.targetHeight :
1400
						0,
1401
				offset = -2 * data.offset[ 1 ],
1402
				newOverTop,
1403
				newOverBottom;
1404
			if ( overTop < 0 ) {
1405
				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
1406
				if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
1407
					position.top += myOffset + atOffset + offset;
1408
				}
1409
			}
1410
			else if ( overBottom > 0 ) {
1411
				newOverTop = position.top -  data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
1412
				if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
1413
					position.top += myOffset + atOffset + offset;
1414
				}
1415
			}
1416
		}
1417
	},
1418
	flipfit: {
1419
		left: function() {
1420
			$.ui.position.flip.left.apply( this, arguments );
1421
			$.ui.position.fit.left.apply( this, arguments );
1422
		},
1423
		top: function() {
1424
			$.ui.position.flip.top.apply( this, arguments );
1425
			$.ui.position.fit.top.apply( this, arguments );
1426
		}
1427
	}
1428
};
1429
1430
// fraction support test
1431
(function () {
1432
	var testElement, testElementParent, testElementStyle, offsetLeft, i,
1433
		body = document.getElementsByTagName( "body" )[ 0 ],
1434
		div = document.createElement( "div" );
1435
1436
	//Create a "fake body" for testing based on method used in jQuery.support
1437
	testElement = document.createElement( body ? "div" : "body" );
1438
	testElementStyle = {
1439
		visibility: "hidden",
1440
		width: 0,
1441
		height: 0,
1442
		border: 0,
1443
		margin: 0,
1444
		background: "none"
1445
	};
1446
	if ( body ) {
1447
		$.extend( testElementStyle, {
1448
			position: "absolute",
1449
			left: "-1000px",
1450
			top: "-1000px"
1451
		});
1452
	}
1453
	for ( i in testElementStyle ) {
1454
		testElement.style[ i ] = testElementStyle[ i ];
1455
	}
1456
	testElement.appendChild( div );
1457
	testElementParent = body || document.documentElement;
1458
	testElementParent.insertBefore( testElement, testElementParent.firstChild );
1459
1460
	div.style.cssText = "position: absolute; left: 10.7432222px;";
1461
1462
	offsetLeft = $( div ).offset().left;
1463
	$.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
1464
1465
	testElement.innerHTML = "";
1466
	testElementParent.removeChild( testElement );
1467
})();
1468
1469
}( jQuery ) );
1470
(function( $, undefined ) {
1471
1472
$.widget("ui.draggable", $.ui.mouse, {
1473
	version: "1.10.3",
1474
	widgetEventPrefix: "drag",
1475
	options: {
1476
		addClasses: true,
1477
		appendTo: "parent",
1478
		axis: false,
1479
		connectToSortable: false,
1480
		containment: false,
1481
		cursor: "auto",
1482
		cursorAt: false,
1483
		grid: false,
1484
		handle: false,
1485
		helper: "original",
1486
		iframeFix: false,
1487
		opacity: false,
1488
		refreshPositions: false,
1489
		revert: false,
1490
		revertDuration: 500,
1491
		scope: "default",
1492
		scroll: true,
1493
		scrollSensitivity: 20,
1494
		scrollSpeed: 20,
1495
		snap: false,
1496
		snapMode: "both",
1497
		snapTolerance: 20,
1498
		stack: false,
1499
		zIndex: false,
1500
1501
		// callbacks
1502
		drag: null,
1503
		start: null,
1504
		stop: null
1505
	},
1506
	_create: function() {
1507
1508
		if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
1509
			this.element[0].style.position = "relative";
1510
		}
1511
		if (this.options.addClasses){
1512
			this.element.addClass("ui-draggable");
1513
		}
1514
		if (this.options.disabled){
1515
			this.element.addClass("ui-draggable-disabled");
1516
		}
1517
1518
		this._mouseInit();
1519
1520
	},
1521
1522
	_destroy: function() {
1523
		this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
1524
		this._mouseDestroy();
1525
	},
1526
1527
	_mouseCapture: function(event) {
1528
1529
		var o = this.options;
1530
1531
		// among others, prevent a drag on a resizable-handle
1532
		if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
1533
			return false;
1534
		}
1535
1536
		//Quit if we're not on a valid handle
1537
		this.handle = this._getHandle(event);
1538
		if (!this.handle) {
1539
			return false;
1540
		}
1541
1542
		$(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
1543
			$("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
1544
			.css({
1545
				width: this.offsetWidth+"px", height: this.offsetHeight+"px",
1546
				position: "absolute", opacity: "0.001", zIndex: 1000
1547
			})
1548
			.css($(this).offset())
1549
			.appendTo("body");
1550
		});
1551
1552
		return true;
1553
1554
	},
1555
1556
	_mouseStart: function(event) {
1557
1558
		var o = this.options;
1559
1560
		//Create and append the visible helper
1561
		this.helper = this._createHelper(event);
1562
1563
		this.helper.addClass("ui-draggable-dragging");
1564
1565
		//Cache the helper size
1566
		this._cacheHelperProportions();
1567
1568
		//If ddmanager is used for droppables, set the global draggable
1569
		if($.ui.ddmanager) {
1570
			$.ui.ddmanager.current = this;
1571
		}
1572
1573
		/*
1574
		 * - Position generation -
1575
		 * This block generates everything position related - it's the core of draggables.
1576
		 */
1577
1578
		//Cache the margins of the original element
1579
		this._cacheMargins();
1580
1581
		//Store the helper's css position
1582
		this.cssPosition = this.helper.css( "position" );
1583
		this.scrollParent = this.helper.scrollParent();
1584
		this.offsetParent = this.helper.offsetParent();
1585
		this.offsetParentCssPosition = this.offsetParent.css( "position" );
1586
1587
		//The element's absolute position on the page minus margins
1588
		this.offset = this.positionAbs = this.element.offset();
1589
		this.offset = {
1590
			top: this.offset.top - this.margins.top,
1591
			left: this.offset.left - this.margins.left
1592
		};
1593
1594
		//Reset scroll cache
1595
		this.offset.scroll = false;
1596
1597
		$.extend(this.offset, {
1598
			click: { //Where the click happened, relative to the element
1599
				left: event.pageX - this.offset.left,
1600
				top: event.pageY - this.offset.top
1601
			},
1602
			parent: this._getParentOffset(),
1603
			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
1604
		});
1605
1606
		//Generate the original position
1607
		this.originalPosition = this.position = this._generatePosition(event);
1608
		this.originalPageX = event.pageX;
1609
		this.originalPageY = event.pageY;
1610
1611
		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
1612
		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
1613
1614
		//Set a containment if given in the options
1615
		this._setContainment();
1616
1617
		//Trigger event + callbacks
1618
		if(this._trigger("start", event) === false) {
1619
			this._clear();
1620
			return false;
1621
		}
1622
1623
		//Recache the helper size
1624
		this._cacheHelperProportions();
1625
1626
		//Prepare the droppable offsets
1627
		if ($.ui.ddmanager && !o.dropBehaviour) {
1628
			$.ui.ddmanager.prepareOffsets(this, event);
1629
		}
1630
1631
1632
		this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
1633
1634
		//If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
1635
		if ( $.ui.ddmanager ) {
1636
			$.ui.ddmanager.dragStart(this, event);
1637
		}
1638
1639
		return true;
1640
	},
1641
1642
	_mouseDrag: function(event, noPropagation) {
1643
		// reset any necessary cached properties (see #5009)
1644
		if ( this.offsetParentCssPosition === "fixed" ) {
1645
			this.offset.parent = this._getParentOffset();
1646
		}
1647
1648
		//Compute the helpers position
1649
		this.position = this._generatePosition(event);
1650
		this.positionAbs = this._convertPositionTo("absolute");
1651
1652
		//Call plugins and callbacks and use the resulting position if something is returned
1653
		if (!noPropagation) {
1654
			var ui = this._uiHash();
1655
			if(this._trigger("drag", event, ui) === false) {
1656
				this._mouseUp({});
1657
				return false;
1658
			}
1659
			this.position = ui.position;
1660
		}
1661
1662
		if(!this.options.axis || this.options.axis !== "y") {
1663
			this.helper[0].style.left = this.position.left+"px";
1664
		}
1665
		if(!this.options.axis || this.options.axis !== "x") {
1666
			this.helper[0].style.top = this.position.top+"px";
1667
		}
1668
		if($.ui.ddmanager) {
1669
			$.ui.ddmanager.drag(this, event);
1670
		}
1671
1672
		return false;
1673
	},
1674
1675
	_mouseStop: function(event) {
1676
1677
		//If we are using droppables, inform the manager about the drop
1678
		var that = this,
1679
			dropped = false;
1680
		if ($.ui.ddmanager && !this.options.dropBehaviour) {
1681
			dropped = $.ui.ddmanager.drop(this, event);
1682
		}
1683
1684
		//if a drop comes from outside (a sortable)
1685
		if(this.dropped) {
1686
			dropped = this.dropped;
1687
			this.dropped = false;
1688
		}
1689
1690
		//if the original element is no longer in the DOM don't bother to continue (see #8269)
1691
		if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) {
1692
			return false;
1693
		}
1694
1695
		if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
1696
			$(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
1697
				if(that._trigger("stop", event) !== false) {
1698
					that._clear();
1699
				}
1700
			});
1701
		} else {
1702
			if(this._trigger("stop", event) !== false) {
1703
				this._clear();
1704
			}
1705
		}
1706
1707
		return false;
1708
	},
1709
1710
	_mouseUp: function(event) {
1711
		//Remove frame helpers
1712
		$("div.ui-draggable-iframeFix").each(function() {
1713
			this.parentNode.removeChild(this);
1714
		});
1715
1716
		//If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
1717
		if( $.ui.ddmanager ) {
1718
			$.ui.ddmanager.dragStop(this, event);
1719
		}
1720
1721
		return $.ui.mouse.prototype._mouseUp.call(this, event);
1722
	},
1723
1724
	cancel: function() {
1725
1726
		if(this.helper.is(".ui-draggable-dragging")) {
1727
			this._mouseUp({});
1728
		} else {
1729
			this._clear();
1730
		}
1731
1732
		return this;
1733
1734
	},
1735
1736
	_getHandle: function(event) {
1737
		return this.options.handle ?
1738
			!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
1739
			true;
1740
	},
1741
1742
	_createHelper: function(event) {
1743
1744
		var o = this.options,
1745
			helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
1746
1747
		if(!helper.parents("body").length) {
1748
			helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
1749
		}
1750
1751
		if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
1752
			helper.css("position", "absolute");
1753
		}
1754
1755
		return helper;
1756
1757
	},
1758
1759
	_adjustOffsetFromHelper: function(obj) {
1760
		if (typeof obj === "string") {
1761
			obj = obj.split(" ");
1762
		}
1763
		if ($.isArray(obj)) {
1764
			obj = {left: +obj[0], top: +obj[1] || 0};
1765
		}
1766
		if ("left" in obj) {
1767
			this.offset.click.left = obj.left + this.margins.left;
1768
		}
1769
		if ("right" in obj) {
1770
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
1771
		}
1772
		if ("top" in obj) {
1773
			this.offset.click.top = obj.top + this.margins.top;
1774
		}
1775
		if ("bottom" in obj) {
1776
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
1777
		}
1778
	},
1779
1780
	_getParentOffset: function() {
1781
1782
		//Get the offsetParent and cache its position
1783
		var po = this.offsetParent.offset();
1784
1785
		// This is a special case where we need to modify a offset calculated on start, since the following happened:
1786
		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
1787
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
1788
		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
1789
		if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
1790
			po.left += this.scrollParent.scrollLeft();
1791
			po.top += this.scrollParent.scrollTop();
1792
		}
1793
1794
		//This needs to be actually done for all browsers, since pageX/pageY includes this information
1795
		//Ugly IE fix
1796
		if((this.offsetParent[0] === document.body) ||
1797
			(this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
1798
			po = { top: 0, left: 0 };
1799
		}
1800
1801
		return {
1802
			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
1803
			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
1804
		};
1805
1806
	},
1807
1808
	_getRelativeOffset: function() {
1809
1810
		if(this.cssPosition === "relative") {
1811
			var p = this.element.position();
1812
			return {
1813
				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
1814
				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
1815
			};
1816
		} else {
1817
			return { top: 0, left: 0 };
1818
		}
1819
1820
	},
1821
1822
	_cacheMargins: function() {
1823
		this.margins = {
1824
			left: (parseInt(this.element.css("marginLeft"),10) || 0),
1825
			top: (parseInt(this.element.css("marginTop"),10) || 0),
1826
			right: (parseInt(this.element.css("marginRight"),10) || 0),
1827
			bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
1828
		};
1829
	},
1830
1831
	_cacheHelperProportions: function() {
1832
		this.helperProportions = {
1833
			width: this.helper.outerWidth(),
1834
			height: this.helper.outerHeight()
1835
		};
1836
	},
1837
1838
	_setContainment: function() {
1839
1840
		var over, c, ce,
1841
			o = this.options;
1842
1843
		if ( !o.containment ) {
1844
			this.containment = null;
1845
			return;
1846
		}
1847
1848
		if ( o.containment === "window" ) {
1849
			this.containment = [
1850
				$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
1851
				$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
1852
				$( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
1853
				$( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
1854
			];
1855
			return;
1856
		}
1857
1858
		if ( o.containment === "document") {
1859
			this.containment = [
1860
				0,
1861
				0,
1862
				$( document ).width() - this.helperProportions.width - this.margins.left,
1863
				( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
1864
			];
1865
			return;
1866
		}
1867
1868
		if ( o.containment.constructor === Array ) {
1869
			this.containment = o.containment;
1870
			return;
1871
		}
1872
1873
		if ( o.containment === "parent" ) {
1874
			o.containment = this.helper[ 0 ].parentNode;
1875
		}
1876
1877
		c = $( o.containment );
1878
		ce = c[ 0 ];
1879
1880
		if( !ce ) {
1881
			return;
1882
		}
1883
1884
		over = c.css( "overflow" ) !== "hidden";
1885
1886
		this.containment = [
1887
			( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
1888
			( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) ,
1889
			( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right,
1890
			( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top  - this.margins.bottom
1891
		];
1892
		this.relative_container = c;
1893
	},
1894
1895
	_convertPositionTo: function(d, pos) {
1896
1897
		if(!pos) {
1898
			pos = this.position;
1899
		}
1900
1901
		var mod = d === "absolute" ? 1 : -1,
1902
			scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent;
1903
1904
		//Cache the scroll
1905
		if (!this.offset.scroll) {
1906
			this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
1907
		}
1908
1909
		return {
1910
			top: (
1911
				pos.top	+																// The absolute mouse position
1912
				this.offset.relative.top * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
1913
				this.offset.parent.top * mod -										// The offsetParent's offset without borders (offset + border)
1914
				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod )
1915
			),
1916
			left: (
1917
				pos.left +																// The absolute mouse position
1918
				this.offset.relative.left * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
1919
				this.offset.parent.left * mod	-										// The offsetParent's offset without borders (offset + border)
1920
				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod )
1921
			)
1922
		};
1923
1924
	},
1925
1926
	_generatePosition: function(event) {
1927
1928
		var containment, co, top, left,
1929
			o = this.options,
1930
			scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent,
1931
			pageX = event.pageX,
1932
			pageY = event.pageY;
1933
1934
		//Cache the scroll
1935
		if (!this.offset.scroll) {
1936
			this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()};
1937
		}
1938
1939
		/*
1940
		 * - Position constraining -
1941
		 * Constrain the position to a mix of grid, containment.
1942
		 */
1943
1944
		// If we are not dragging yet, we won't check for options
1945
		if ( this.originalPosition ) {
1946
			if ( this.containment ) {
1947
				if ( this.relative_container ){
1948
					co = this.relative_container.offset();
1949
					containment = [
1950
						this.containment[ 0 ] + co.left,
1951
						this.containment[ 1 ] + co.top,
1952
						this.containment[ 2 ] + co.left,
1953
						this.containment[ 3 ] + co.top
1954
					];
1955
				}
1956
				else {
1957
					containment = this.containment;
1958
				}
1959
1960
				if(event.pageX - this.offset.click.left < containment[0]) {
1961
					pageX = containment[0] + this.offset.click.left;
1962
				}
1963
				if(event.pageY - this.offset.click.top < containment[1]) {
1964
					pageY = containment[1] + this.offset.click.top;
1965
				}
1966
				if(event.pageX - this.offset.click.left > containment[2]) {
1967
					pageX = containment[2] + this.offset.click.left;
1968
				}
1969
				if(event.pageY - this.offset.click.top > containment[3]) {
1970
					pageY = containment[3] + this.offset.click.top;
1971
				}
1972
			}
1973
1974
			if(o.grid) {
1975
				//Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
1976
				top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
1977
				pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
1978
1979
				left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
1980
				pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
1981
			}
1982
1983
		}
1984
1985
		return {
1986
			top: (
1987
				pageY -																	// The absolute mouse position
1988
				this.offset.click.top	-												// Click offset (relative to the element)
1989
				this.offset.relative.top -												// Only for relative positioned nodes: Relative offset from element to offset parent
1990
				this.offset.parent.top +												// The offsetParent's offset without borders (offset + border)
1991
				( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top )
1992
			),
1993
			left: (
1994
				pageX -																	// The absolute mouse position
1995
				this.offset.click.left -												// Click offset (relative to the element)
1996
				this.offset.relative.left -												// Only for relative positioned nodes: Relative offset from element to offset parent
1997
				this.offset.parent.left +												// The offsetParent's offset without borders (offset + border)
1998
				( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left )
1999
			)
2000
		};
2001
2002
	},
2003
2004
	_clear: function() {
2005
		this.helper.removeClass("ui-draggable-dragging");
2006
		if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
2007
			this.helper.remove();
2008
		}
2009
		this.helper = null;
2010
		this.cancelHelperRemoval = false;
2011
	},
2012
2013
	// From now on bulk stuff - mainly helpers
2014
2015
	_trigger: function(type, event, ui) {
2016
		ui = ui || this._uiHash();
2017
		$.ui.plugin.call(this, type, [event, ui]);
2018
		//The absolute position has to be recalculated after plugins
2019
		if(type === "drag") {
2020
			this.positionAbs = this._convertPositionTo("absolute");
2021
		}
2022
		return $.Widget.prototype._trigger.call(this, type, event, ui);
2023
	},
2024
2025
	plugins: {},
2026
2027
	_uiHash: function() {
2028
		return {
2029
			helper: this.helper,
2030
			position: this.position,
2031
			originalPosition: this.originalPosition,
2032
			offset: this.positionAbs
2033
		};
2034
	}
2035
2036
});
2037
2038
$.ui.plugin.add("draggable", "connectToSortable", {
2039
	start: function(event, ui) {
2040
2041
		var inst = $(this).data("ui-draggable"), o = inst.options,
2042
			uiSortable = $.extend({}, ui, { item: inst.element });
2043
		inst.sortables = [];
2044
		$(o.connectToSortable).each(function() {
2045
			var sortable = $.data(this, "ui-sortable");
2046
			if (sortable && !sortable.options.disabled) {
2047
				inst.sortables.push({
2048
					instance: sortable,
2049
					shouldRevert: sortable.options.revert
2050
				});
2051
				sortable.refreshPositions();	// Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
2052
				sortable._trigger("activate", event, uiSortable);
2053
			}
2054
		});
2055
2056
	},
2057
	stop: function(event, ui) {
2058
2059
		//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
2060
		var inst = $(this).data("ui-draggable"),
2061
			uiSortable = $.extend({}, ui, { item: inst.element });
2062
2063
		$.each(inst.sortables, function() {
2064
			if(this.instance.isOver) {
2065
2066
				this.instance.isOver = 0;
2067
2068
				inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
2069
				this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
2070
2071
				//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
2072
				if(this.shouldRevert) {
2073
					this.instance.options.revert = this.shouldRevert;
2074
				}
2075
2076
				//Trigger the stop of the sortable
2077
				this.instance._mouseStop(event);
2078
2079
				this.instance.options.helper = this.instance.options._helper;
2080
2081
				//If the helper has been the original item, restore properties in the sortable
2082
				if(inst.options.helper === "original") {
2083
					this.instance.currentItem.css({ top: "auto", left: "auto" });
2084
				}
2085
2086
			} else {
2087
				this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
2088
				this.instance._trigger("deactivate", event, uiSortable);
2089
			}
2090
2091
		});
2092
2093
	},
2094
	drag: function(event, ui) {
2095
2096
		var inst = $(this).data("ui-draggable"), that = this;
2097
2098
		$.each(inst.sortables, function() {
2099
2100
			var innermostIntersecting = false,
2101
				thisSortable = this;
2102
2103
			//Copy over some variables to allow calling the sortable's native _intersectsWith
2104
			this.instance.positionAbs = inst.positionAbs;
2105
			this.instance.helperProportions = inst.helperProportions;
2106
			this.instance.offset.click = inst.offset.click;
2107
2108
			if(this.instance._intersectsWith(this.instance.containerCache)) {
2109
				innermostIntersecting = true;
2110
				$.each(inst.sortables, function () {
2111
					this.instance.positionAbs = inst.positionAbs;
2112
					this.instance.helperProportions = inst.helperProportions;
2113
					this.instance.offset.click = inst.offset.click;
2114
					if (this !== thisSortable &&
2115
						this.instance._intersectsWith(this.instance.containerCache) &&
2116
						$.contains(thisSortable.instance.element[0], this.instance.element[0])
2117
					) {
2118
						innermostIntersecting = false;
2119
					}
2120
					return innermostIntersecting;
2121
				});
2122
			}
2123
2124
2125
			if(innermostIntersecting) {
2126
				//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
2127
				if(!this.instance.isOver) {
2128
2129
					this.instance.isOver = 1;
2130
					//Now we fake the start of dragging for the sortable instance,
2131
					//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
2132
					//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
2133
					this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
2134
					this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
2135
					this.instance.options.helper = function() { return ui.helper[0]; };
2136
2137
					event.target = this.instance.currentItem[0];
2138
					this.instance._mouseCapture(event, true);
2139
					this.instance._mouseStart(event, true, true);
2140
2141
					//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
2142
					this.instance.offset.click.top = inst.offset.click.top;
2143
					this.instance.offset.click.left = inst.offset.click.left;
2144
					this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
2145
					this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
2146
2147
					inst._trigger("toSortable", event);
2148
					inst.dropped = this.instance.element; //draggable revert needs that
2149
					//hack so receive/update callbacks work (mostly)
2150
					inst.currentItem = inst.element;
2151
					this.instance.fromOutside = inst;
2152
2153
				}
2154
2155
				//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
2156
				if(this.instance.currentItem) {
2157
					this.instance._mouseDrag(event);
2158
				}
2159
2160
			} else {
2161
2162
				//If it doesn't intersect with the sortable, and it intersected before,
2163
				//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
2164
				if(this.instance.isOver) {
2165
2166
					this.instance.isOver = 0;
2167
					this.instance.cancelHelperRemoval = true;
2168
2169
					//Prevent reverting on this forced stop
2170
					this.instance.options.revert = false;
2171
2172
					// The out event needs to be triggered independently
2173
					this.instance._trigger("out", event, this.instance._uiHash(this.instance));
2174
2175
					this.instance._mouseStop(event, true);
2176
					this.instance.options.helper = this.instance.options._helper;
2177
2178
					//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
2179
					this.instance.currentItem.remove();
2180
					if(this.instance.placeholder) {
2181
						this.instance.placeholder.remove();
2182
					}
2183
2184
					inst._trigger("fromSortable", event);
2185
					inst.dropped = false; //draggable revert needs that
2186
				}
2187
2188
			}
2189
2190
		});
2191
2192
	}
2193
});
2194
2195
$.ui.plugin.add("draggable", "cursor", {
2196
	start: function() {
2197
		var t = $("body"), o = $(this).data("ui-draggable").options;
2198
		if (t.css("cursor")) {
2199
			o._cursor = t.css("cursor");
2200
		}
2201
		t.css("cursor", o.cursor);
2202
	},
2203
	stop: function() {
2204
		var o = $(this).data("ui-draggable").options;
2205
		if (o._cursor) {
2206
			$("body").css("cursor", o._cursor);
2207
		}
2208
	}
2209
});
2210
2211
$.ui.plugin.add("draggable", "opacity", {
2212
	start: function(event, ui) {
2213
		var t = $(ui.helper), o = $(this).data("ui-draggable").options;
2214
		if(t.css("opacity")) {
2215
			o._opacity = t.css("opacity");
2216
		}
2217
		t.css("opacity", o.opacity);
2218
	},
2219
	stop: function(event, ui) {
2220
		var o = $(this).data("ui-draggable").options;
2221
		if(o._opacity) {
2222
			$(ui.helper).css("opacity", o._opacity);
2223
		}
2224
	}
2225
});
2226
2227
$.ui.plugin.add("draggable", "scroll", {
2228
	start: function() {
2229
		var i = $(this).data("ui-draggable");
2230
		if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
2231
			i.overflowOffset = i.scrollParent.offset();
2232
		}
2233
	},
2234
	drag: function( event ) {
2235
2236
		var i = $(this).data("ui-draggable"), o = i.options, scrolled = false;
2237
2238
		if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") {
2239
2240
			if(!o.axis || o.axis !== "x") {
2241
				if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
2242
					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
2243
				} else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
2244
					i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
2245
				}
2246
			}
2247
2248
			if(!o.axis || o.axis !== "y") {
2249
				if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
2250
					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
2251
				} else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
2252
					i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
2253
				}
2254
			}
2255
2256
		} else {
2257
2258
			if(!o.axis || o.axis !== "x") {
2259
				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
2260
					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
2261
				} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
2262
					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
2263
				}
2264
			}
2265
2266
			if(!o.axis || o.axis !== "y") {
2267
				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
2268
					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
2269
				} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
2270
					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
2271
				}
2272
			}
2273
2274
		}
2275
2276
		if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
2277
			$.ui.ddmanager.prepareOffsets(i, event);
2278
		}
2279
2280
	}
2281
});
2282
2283
$.ui.plugin.add("draggable", "snap", {
2284
	start: function() {
2285
2286
		var i = $(this).data("ui-draggable"),
2287
			o = i.options;
2288
2289
		i.snapElements = [];
2290
2291
		$(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
2292
			var $t = $(this),
2293
				$o = $t.offset();
2294
			if(this !== i.element[0]) {
2295
				i.snapElements.push({
2296
					item: this,
2297
					width: $t.outerWidth(), height: $t.outerHeight(),
2298
					top: $o.top, left: $o.left
2299
				});
2300
			}
2301
		});
2302
2303
	},
2304
	drag: function(event, ui) {
2305
2306
		var ts, bs, ls, rs, l, r, t, b, i, first,
2307
			inst = $(this).data("ui-draggable"),
2308
			o = inst.options,
2309
			d = o.snapTolerance,
2310
			x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
2311
			y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
2312
2313
		for (i = inst.snapElements.length - 1; i >= 0; i--){
2314
2315
			l = inst.snapElements[i].left;
2316
			r = l + inst.snapElements[i].width;
2317
			t = inst.snapElements[i].top;
2318
			b = t + inst.snapElements[i].height;
2319
2320
			if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
2321
				if(inst.snapElements[i].snapping) {
2322
					(inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2323
				}
2324
				inst.snapElements[i].snapping = false;
2325
				continue;
2326
			}
2327
2328
			if(o.snapMode !== "inner") {
2329
				ts = Math.abs(t - y2) <= d;
2330
				bs = Math.abs(b - y1) <= d;
2331
				ls = Math.abs(l - x2) <= d;
2332
				rs = Math.abs(r - x1) <= d;
2333
				if(ts) {
2334
					ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
2335
				}
2336
				if(bs) {
2337
					ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
2338
				}
2339
				if(ls) {
2340
					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
2341
				}
2342
				if(rs) {
2343
					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
2344
				}
2345
			}
2346
2347
			first = (ts || bs || ls || rs);
2348
2349
			if(o.snapMode !== "outer") {
2350
				ts = Math.abs(t - y1) <= d;
2351
				bs = Math.abs(b - y2) <= d;
2352
				ls = Math.abs(l - x1) <= d;
2353
				rs = Math.abs(r - x2) <= d;
2354
				if(ts) {
2355
					ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
2356
				}
2357
				if(bs) {
2358
					ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
2359
				}
2360
				if(ls) {
2361
					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
2362
				}
2363
				if(rs) {
2364
					ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
2365
				}
2366
			}
2367
2368
			if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
2369
				(inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
2370
			}
2371
			inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
2372
2373
		}
2374
2375
	}
2376
});
2377
2378
$.ui.plugin.add("draggable", "stack", {
2379
	start: function() {
2380
		var min,
2381
			o = this.data("ui-draggable").options,
2382
			group = $.makeArray($(o.stack)).sort(function(a,b) {
2383
				return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
2384
			});
2385
2386
		if (!group.length) { return; }
2387
2388
		min = parseInt($(group[0]).css("zIndex"), 10) || 0;
2389
		$(group).each(function(i) {
2390
			$(this).css("zIndex", min + i);
2391
		});
2392
		this.css("zIndex", (min + group.length));
2393
	}
2394
});
2395
2396
$.ui.plugin.add("draggable", "zIndex", {
2397
	start: function(event, ui) {
2398
		var t = $(ui.helper), o = $(this).data("ui-draggable").options;
2399
		if(t.css("zIndex")) {
2400
			o._zIndex = t.css("zIndex");
2401
		}
2402
		t.css("zIndex", o.zIndex);
2403
	},
2404
	stop: function(event, ui) {
2405
		var o = $(this).data("ui-draggable").options;
2406
		if(o._zIndex) {
2407
			$(ui.helper).css("zIndex", o._zIndex);
2408
		}
2409
	}
2410
});
2411
2412
})(jQuery);
2413
(function( $, undefined ) {
2414
2415
function isOverAxis( x, reference, size ) {
2416
	return ( x > reference ) && ( x < ( reference + size ) );
2417
}
2418
2419
$.widget("ui.droppable", {
2420
	version: "1.10.3",
2421
	widgetEventPrefix: "drop",
2422
	options: {
2423
		accept: "*",
2424
		activeClass: false,
2425
		addClasses: true,
2426
		greedy: false,
2427
		hoverClass: false,
2428
		scope: "default",
2429
		tolerance: "intersect",
2430
2431
		// callbacks
2432
		activate: null,
2433
		deactivate: null,
2434
		drop: null,
2435
		out: null,
2436
		over: null
2437
	},
2438
	_create: function() {
2439
2440
		var o = this.options,
2441
			accept = o.accept;
2442
2443
		this.isover = false;
2444
		this.isout = true;
2445
2446
		this.accept = $.isFunction(accept) ? accept : function(d) {
2447
			return d.is(accept);
2448
		};
2449
2450
		//Store the droppable's proportions
2451
		this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
2452
2453
		// Add the reference and positions to the manager
2454
		$.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
2455
		$.ui.ddmanager.droppables[o.scope].push(this);
2456
2457
		(o.addClasses && this.element.addClass("ui-droppable"));
2458
2459
	},
2460
2461
	_destroy: function() {
2462
		var i = 0,
2463
			drop = $.ui.ddmanager.droppables[this.options.scope];
2464
2465
		for ( ; i < drop.length; i++ ) {
2466
			if ( drop[i] === this ) {
2467
				drop.splice(i, 1);
2468
			}
2469
		}
2470
2471
		this.element.removeClass("ui-droppable ui-droppable-disabled");
2472
	},
2473
2474
	_setOption: function(key, value) {
2475
2476
		if(key === "accept") {
2477
			this.accept = $.isFunction(value) ? value : function(d) {
2478
				return d.is(value);
2479
			};
2480
		}
2481
		$.Widget.prototype._setOption.apply(this, arguments);
2482
	},
2483
2484
	_activate: function(event) {
2485
		var draggable = $.ui.ddmanager.current;
2486
		if(this.options.activeClass) {
2487
			this.element.addClass(this.options.activeClass);
2488
		}
2489
		if(draggable){
2490
			this._trigger("activate", event, this.ui(draggable));
2491
		}
2492
	},
2493
2494
	_deactivate: function(event) {
2495
		var draggable = $.ui.ddmanager.current;
2496
		if(this.options.activeClass) {
2497
			this.element.removeClass(this.options.activeClass);
2498
		}
2499
		if(draggable){
2500
			this._trigger("deactivate", event, this.ui(draggable));
2501
		}
2502
	},
2503
2504
	_over: function(event) {
2505
2506
		var draggable = $.ui.ddmanager.current;
2507
2508
		// Bail if draggable and droppable are same element
2509
		if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2510
			return;
2511
		}
2512
2513
		if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2514
			if(this.options.hoverClass) {
2515
				this.element.addClass(this.options.hoverClass);
2516
			}
2517
			this._trigger("over", event, this.ui(draggable));
2518
		}
2519
2520
	},
2521
2522
	_out: function(event) {
2523
2524
		var draggable = $.ui.ddmanager.current;
2525
2526
		// Bail if draggable and droppable are same element
2527
		if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2528
			return;
2529
		}
2530
2531
		if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2532
			if(this.options.hoverClass) {
2533
				this.element.removeClass(this.options.hoverClass);
2534
			}
2535
			this._trigger("out", event, this.ui(draggable));
2536
		}
2537
2538
	},
2539
2540
	_drop: function(event,custom) {
2541
2542
		var draggable = custom || $.ui.ddmanager.current,
2543
			childrenIntersection = false;
2544
2545
		// Bail if draggable and droppable are same element
2546
		if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) {
2547
			return false;
2548
		}
2549
2550
		this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() {
2551
			var inst = $.data(this, "ui-droppable");
2552
			if(
2553
				inst.options.greedy &&
2554
				!inst.options.disabled &&
2555
				inst.options.scope === draggable.options.scope &&
2556
				inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) &&
2557
				$.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
2558
			) { childrenIntersection = true; return false; }
2559
		});
2560
		if(childrenIntersection) {
2561
			return false;
2562
		}
2563
2564
		if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2565
			if(this.options.activeClass) {
2566
				this.element.removeClass(this.options.activeClass);
2567
			}
2568
			if(this.options.hoverClass) {
2569
				this.element.removeClass(this.options.hoverClass);
2570
			}
2571
			this._trigger("drop", event, this.ui(draggable));
2572
			return this.element;
2573
		}
2574
2575
		return false;
2576
2577
	},
2578
2579
	ui: function(c) {
2580
		return {
2581
			draggable: (c.currentItem || c.element),
2582
			helper: c.helper,
2583
			position: c.position,
2584
			offset: c.positionAbs
2585
		};
2586
	}
2587
2588
});
2589
2590
$.ui.intersect = function(draggable, droppable, toleranceMode) {
2591
2592
	if (!droppable.offset) {
2593
		return false;
2594
	}
2595
2596
	var draggableLeft, draggableTop,
2597
		x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
2598
		y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height,
2599
		l = droppable.offset.left, r = l + droppable.proportions.width,
2600
		t = droppable.offset.top, b = t + droppable.proportions.height;
2601
2602
	switch (toleranceMode) {
2603
		case "fit":
2604
			return (l <= x1 && x2 <= r && t <= y1 && y2 <= b);
2605
		case "intersect":
2606
			return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half
2607
				x2 - (draggable.helperProportions.width / 2) < r && // Left Half
2608
				t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half
2609
				y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
2610
		case "pointer":
2611
			draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left);
2612
			draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top);
2613
			return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width );
2614
		case "touch":
2615
			return (
2616
				(y1 >= t && y1 <= b) ||	// Top edge touching
2617
				(y2 >= t && y2 <= b) ||	// Bottom edge touching
2618
				(y1 < t && y2 > b)		// Surrounded vertically
2619
			) && (
2620
				(x1 >= l && x1 <= r) ||	// Left edge touching
2621
				(x2 >= l && x2 <= r) ||	// Right edge touching
2622
				(x1 < l && x2 > r)		// Surrounded horizontally
2623
			);
2624
		default:
2625
			return false;
2626
		}
2627
2628
};
2629
2630
/*
2631
	This manager tracks offsets of draggables and droppables
2632
*/
2633
$.ui.ddmanager = {
2634
	current: null,
2635
	droppables: { "default": [] },
2636
	prepareOffsets: function(t, event) {
2637
2638
		var i, j,
2639
			m = $.ui.ddmanager.droppables[t.options.scope] || [],
2640
			type = event ? event.type : null, // workaround for #2317
2641
			list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack();
2642
2643
		droppablesLoop: for (i = 0; i < m.length; i++) {
2644
2645
			//No disabled and non-accepted
2646
			if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) {
2647
				continue;
2648
			}
2649
2650
			// Filter out elements in the current dragged item
2651
			for (j=0; j < list.length; j++) {
2652
				if(list[j] === m[i].element[0]) {
2653
					m[i].proportions.height = 0;
2654
					continue droppablesLoop;
2655
				}
2656
			}
2657
2658
			m[i].visible = m[i].element.css("display") !== "none";
2659
			if(!m[i].visible) {
2660
				continue;
2661
			}
2662
2663
			//Activate the droppable if used directly from draggables
2664
			if(type === "mousedown") {
2665
				m[i]._activate.call(m[i], event);
2666
			}
2667
2668
			m[i].offset = m[i].element.offset();
2669
			m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
2670
2671
		}
2672
2673
	},
2674
	drop: function(draggable, event) {
2675
2676
		var dropped = false;
2677
		// Create a copy of the droppables in case the list changes during the drop (#9116)
2678
		$.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() {
2679
2680
			if(!this.options) {
2681
				return;
2682
			}
2683
			if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) {
2684
				dropped = this._drop.call(this, event) || dropped;
2685
			}
2686
2687
			if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
2688
				this.isout = true;
2689
				this.isover = false;
2690
				this._deactivate.call(this, event);
2691
			}
2692
2693
		});
2694
		return dropped;
2695
2696
	},
2697
	dragStart: function( draggable, event ) {
2698
		//Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
2699
		draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
2700
			if( !draggable.options.refreshPositions ) {
2701
				$.ui.ddmanager.prepareOffsets( draggable, event );
2702
			}
2703
		});
2704
	},
2705
	drag: function(draggable, event) {
2706
2707
		//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
2708
		if(draggable.options.refreshPositions) {
2709
			$.ui.ddmanager.prepareOffsets(draggable, event);
2710
		}
2711
2712
		//Run through all droppables and check their positions based on specific tolerance options
2713
		$.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
2714
2715
			if(this.options.disabled || this.greedyChild || !this.visible) {
2716
				return;
2717
			}
2718
2719
			var parentInstance, scope, parent,
2720
				intersects = $.ui.intersect(draggable, this, this.options.tolerance),
2721
				c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null);
2722
			if(!c) {
2723
				return;
2724
			}
2725
2726
			if (this.options.greedy) {
2727
				// find droppable parents with same scope
2728
				scope = this.options.scope;
2729
				parent = this.element.parents(":data(ui-droppable)").filter(function () {
2730
					return $.data(this, "ui-droppable").options.scope === scope;
2731
				});
2732
2733
				if (parent.length) {
2734
					parentInstance = $.data(parent[0], "ui-droppable");
2735
					parentInstance.greedyChild = (c === "isover");
2736
				}
2737
			}
2738
2739
			// we just moved into a greedy child
2740
			if (parentInstance && c === "isover") {
2741
				parentInstance.isover = false;
2742
				parentInstance.isout = true;
2743
				parentInstance._out.call(parentInstance, event);
2744
			}
2745
2746
			this[c] = true;
2747
			this[c === "isout" ? "isover" : "isout"] = false;
2748
			this[c === "isover" ? "_over" : "_out"].call(this, event);
2749
2750
			// we just moved out of a greedy child
2751
			if (parentInstance && c === "isout") {
2752
				parentInstance.isout = false;
2753
				parentInstance.isover = true;
2754
				parentInstance._over.call(parentInstance, event);
2755
			}
2756
		});
2757
2758
	},
2759
	dragStop: function( draggable, event ) {
2760
		draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
2761
		//Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
2762
		if( !draggable.options.refreshPositions ) {
2763
			$.ui.ddmanager.prepareOffsets( draggable, event );
2764
		}
2765
	}
2766
};
2767
2768
})(jQuery);
2769
(function( $, undefined ) {
2770
2771
function num(v) {
2772
	return parseInt(v, 10) || 0;
2773
}
2774
2775
function isNumber(value) {
2776
	return !isNaN(parseInt(value, 10));
2777
}
2778
2779
$.widget("ui.resizable", $.ui.mouse, {
2780
	version: "1.10.3",
2781
	widgetEventPrefix: "resize",
2782
	options: {
2783
		alsoResize: false,
2784
		animate: false,
2785
		animateDuration: "slow",
2786
		animateEasing: "swing",
2787
		aspectRatio: false,
2788
		autoHide: false,
2789
		containment: false,
2790
		ghost: false,
2791
		grid: false,
2792
		handles: "e,s,se",
2793
		helper: false,
2794
		maxHeight: null,
2795
		maxWidth: null,
2796
		minHeight: 10,
2797
		minWidth: 10,
2798
		// See #7960
2799
		zIndex: 90,
2800
2801
		// callbacks
2802
		resize: null,
2803
		start: null,
2804
		stop: null
2805
	},
2806
	_create: function() {
2807
2808
		var n, i, handle, axis, hname,
2809
			that = this,
2810
			o = this.options;
2811
		this.element.addClass("ui-resizable");
2812
2813
		$.extend(this, {
2814
			_aspectRatio: !!(o.aspectRatio),
2815
			aspectRatio: o.aspectRatio,
2816
			originalElement: this.element,
2817
			_proportionallyResizeElements: [],
2818
			_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
2819
		});
2820
2821
		//Wrap the element if it cannot hold child nodes
2822
		if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
2823
2824
			//Create a wrapper element and set the wrapper to the new current internal element
2825
			this.element.wrap(
2826
				$("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
2827
					position: this.element.css("position"),
2828
					width: this.element.outerWidth(),
2829
					height: this.element.outerHeight(),
2830
					top: this.element.css("top"),
2831
					left: this.element.css("left")
2832
				})
2833
			);
2834
2835
			//Overwrite the original this.element
2836
			this.element = this.element.parent().data(
2837
				"ui-resizable", this.element.data("ui-resizable")
2838
			);
2839
2840
			this.elementIsWrapper = true;
2841
2842
			//Move margins to the wrapper
2843
			this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
2844
			this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
2845
2846
			//Prevent Safari textarea resize
2847
			this.originalResizeStyle = this.originalElement.css("resize");
2848
			this.originalElement.css("resize", "none");
2849
2850
			//Push the actual element to our proportionallyResize internal array
2851
			this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
2852
2853
			// avoid IE jump (hard set the margin)
2854
			this.originalElement.css({ margin: this.originalElement.css("margin") });
2855
2856
			// fix handlers offset
2857
			this._proportionallyResize();
2858
2859
		}
2860
2861
		this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
2862
		if(this.handles.constructor === String) {
2863
2864
			if ( this.handles === "all") {
2865
				this.handles = "n,e,s,w,se,sw,ne,nw";
2866
			}
2867
2868
			n = this.handles.split(",");
2869
			this.handles = {};
2870
2871
			for(i = 0; i < n.length; i++) {
2872
2873
				handle = $.trim(n[i]);
2874
				hname = "ui-resizable-"+handle;
2875
				axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
2876
2877
				// Apply zIndex to all handles - see #7960
2878
				axis.css({ zIndex: o.zIndex });
2879
2880
				//TODO : What's going on here?
2881
				if ("se" === handle) {
2882
					axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
2883
				}
2884
2885
				//Insert into internal handles object and append to element
2886
				this.handles[handle] = ".ui-resizable-"+handle;
2887
				this.element.append(axis);
2888
			}
2889
2890
		}
2891
2892
		this._renderAxis = function(target) {
2893
2894
			var i, axis, padPos, padWrapper;
2895
2896
			target = target || this.element;
2897
2898
			for(i in this.handles) {
2899
2900
				if(this.handles[i].constructor === String) {
2901
					this.handles[i] = $(this.handles[i], this.element).show();
2902
				}
2903
2904
				//Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
2905
				if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
2906
2907
					axis = $(this.handles[i], this.element);
2908
2909
					//Checking the correct pad and border
2910
					padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
2911
2912
					//The padding type i have to apply...
2913
					padPos = [ "padding",
2914
						/ne|nw|n/.test(i) ? "Top" :
2915
						/se|sw|s/.test(i) ? "Bottom" :
2916
						/^e$/.test(i) ? "Right" : "Left" ].join("");
2917
2918
					target.css(padPos, padWrapper);
2919
2920
					this._proportionallyResize();
2921
2922
				}
2923
2924
				//TODO: What's that good for? There's not anything to be executed left
2925
				if(!$(this.handles[i]).length) {
2926
					continue;
2927
				}
2928
			}
2929
		};
2930
2931
		//TODO: make renderAxis a prototype function
2932
		this._renderAxis(this.element);
2933
2934
		this._handles = $(".ui-resizable-handle", this.element)
2935
			.disableSelection();
2936
2937
		//Matching axis name
2938
		this._handles.mouseover(function() {
2939
			if (!that.resizing) {
2940
				if (this.className) {
2941
					axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
2942
				}
2943
				//Axis, default = se
2944
				that.axis = axis && axis[1] ? axis[1] : "se";
2945
			}
2946
		});
2947
2948
		//If we want to auto hide the elements
2949
		if (o.autoHide) {
2950
			this._handles.hide();
2951
			$(this.element)
2952
				.addClass("ui-resizable-autohide")
2953
				.mouseenter(function() {
2954
					if (o.disabled) {
2955
						return;
2956
					}
2957
					$(this).removeClass("ui-resizable-autohide");
2958
					that._handles.show();
2959
				})
2960
				.mouseleave(function(){
2961
					if (o.disabled) {
2962
						return;
2963
					}
2964
					if (!that.resizing) {
2965
						$(this).addClass("ui-resizable-autohide");
2966
						that._handles.hide();
2967
					}
2968
				});
2969
		}
2970
2971
		//Initialize the mouse interaction
2972
		this._mouseInit();
2973
2974
	},
2975
2976
	_destroy: function() {
2977
2978
		this._mouseDestroy();
2979
2980
		var wrapper,
2981
			_destroy = function(exp) {
2982
				$(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
2983
					.removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
2984
			};
2985
2986
		//TODO: Unwrap at same DOM position
2987
		if (this.elementIsWrapper) {
2988
			_destroy(this.element);
2989
			wrapper = this.element;
2990
			this.originalElement.css({
2991
				position: wrapper.css("position"),
2992
				width: wrapper.outerWidth(),
2993
				height: wrapper.outerHeight(),
2994
				top: wrapper.css("top"),
2995
				left: wrapper.css("left")
2996
			}).insertAfter( wrapper );
2997
			wrapper.remove();
2998
		}
2999
3000
		this.originalElement.css("resize", this.originalResizeStyle);
3001
		_destroy(this.originalElement);
3002
3003
		return this;
3004
	},
3005
3006
	_mouseCapture: function(event) {
3007
		var i, handle,
3008
			capture = false;
3009
3010
		for (i in this.handles) {
3011
			handle = $(this.handles[i])[0];
3012
			if (handle === event.target || $.contains(handle, event.target)) {
3013
				capture = true;
3014
			}
3015
		}
3016
3017
		return !this.options.disabled && capture;
3018
	},
3019
3020
	_mouseStart: function(event) {
3021
3022
		var curleft, curtop, cursor,
3023
			o = this.options,
3024
			iniPos = this.element.position(),
3025
			el = this.element;
3026
3027
		this.resizing = true;
3028
3029
		// bugfix for http://dev.jquery.com/ticket/1749
3030
		if ( (/absolute/).test( el.css("position") ) ) {
3031
			el.css({ position: "absolute", top: el.css("top"), left: el.css("left") });
3032
		} else if (el.is(".ui-draggable")) {
3033
			el.css({ position: "absolute", top: iniPos.top, left: iniPos.left });
3034
		}
3035
3036
		this._renderProxy();
3037
3038
		curleft = num(this.helper.css("left"));
3039
		curtop = num(this.helper.css("top"));
3040
3041
		if (o.containment) {
3042
			curleft += $(o.containment).scrollLeft() || 0;
3043
			curtop += $(o.containment).scrollTop() || 0;
3044
		}
3045
3046
		//Store needed variables
3047
		this.offset = this.helper.offset();
3048
		this.position = { left: curleft, top: curtop };
3049
		this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
3050
		this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
3051
		this.originalPosition = { left: curleft, top: curtop };
3052
		this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
3053
		this.originalMousePosition = { left: event.pageX, top: event.pageY };
3054
3055
		//Aspect Ratio
3056
		this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
3057
3058
		cursor = $(".ui-resizable-" + this.axis).css("cursor");
3059
		$("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
3060
3061
		el.addClass("ui-resizable-resizing");
3062
		this._propagate("start", event);
3063
		return true;
3064
	},
3065
3066
	_mouseDrag: function(event) {
3067
3068
		//Increase performance, avoid regex
3069
		var data,
3070
			el = this.helper, props = {},
3071
			smp = this.originalMousePosition,
3072
			a = this.axis,
3073
			prevTop = this.position.top,
3074
			prevLeft = this.position.left,
3075
			prevWidth = this.size.width,
3076
			prevHeight = this.size.height,
3077
			dx = (event.pageX-smp.left)||0,
3078
			dy = (event.pageY-smp.top)||0,
3079
			trigger = this._change[a];
3080
3081
		if (!trigger) {
3082
			return false;
3083
		}
3084
3085
		// Calculate the attrs that will be change
3086
		data = trigger.apply(this, [event, dx, dy]);
3087
3088
		// Put this in the mouseDrag handler since the user can start pressing shift while resizing
3089
		this._updateVirtualBoundaries(event.shiftKey);
3090
		if (this._aspectRatio || event.shiftKey) {
3091
			data = this._updateRatio(data, event);
3092
		}
3093
3094
		data = this._respectSize(data, event);
3095
3096
		this._updateCache(data);
3097
3098
		// plugins callbacks need to be called first
3099
		this._propagate("resize", event);
3100
3101
		if (this.position.top !== prevTop) {
3102
			props.top = this.position.top + "px";
3103
		}
3104
		if (this.position.left !== prevLeft) {
3105
			props.left = this.position.left + "px";
3106
		}
3107
		if (this.size.width !== prevWidth) {
3108
			props.width = this.size.width + "px";
3109
		}
3110
		if (this.size.height !== prevHeight) {
3111
			props.height = this.size.height + "px";
3112
		}
3113
		el.css(props);
3114
3115
		if (!this._helper && this._proportionallyResizeElements.length) {
3116
			this._proportionallyResize();
3117
		}
3118
3119
		// Call the user callback if the element was resized
3120
		if ( ! $.isEmptyObject(props) ) {
3121
			this._trigger("resize", event, this.ui());
3122
		}
3123
3124
		return false;
3125
	},
3126
3127
	_mouseStop: function(event) {
3128
3129
		this.resizing = false;
3130
		var pr, ista, soffseth, soffsetw, s, left, top,
3131
			o = this.options, that = this;
3132
3133
		if(this._helper) {
3134
3135
			pr = this._proportionallyResizeElements;
3136
			ista = pr.length && (/textarea/i).test(pr[0].nodeName);
3137
			soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
3138
			soffsetw = ista ? 0 : that.sizeDiff.width;
3139
3140
			s = { width: (that.helper.width()  - soffsetw), height: (that.helper.height() - soffseth) };
3141
			left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
3142
			top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
3143
3144
			if (!o.animate) {
3145
				this.element.css($.extend(s, { top: top, left: left }));
3146
			}
3147
3148
			that.helper.height(that.size.height);
3149
			that.helper.width(that.size.width);
3150
3151
			if (this._helper && !o.animate) {
3152
				this._proportionallyResize();
3153
			}
3154
		}
3155
3156
		$("body").css("cursor", "auto");
3157
3158
		this.element.removeClass("ui-resizable-resizing");
3159
3160
		this._propagate("stop", event);
3161
3162
		if (this._helper) {
3163
			this.helper.remove();
3164
		}
3165
3166
		return false;
3167
3168
	},
3169
3170
	_updateVirtualBoundaries: function(forceAspectRatio) {
3171
		var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
3172
			o = this.options;
3173
3174
		b = {
3175
			minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
3176
			maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
3177
			minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
3178
			maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
3179
		};
3180
3181
		if(this._aspectRatio || forceAspectRatio) {
3182
			// We want to create an enclosing box whose aspect ration is the requested one
3183
			// First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
3184
			pMinWidth = b.minHeight * this.aspectRatio;
3185
			pMinHeight = b.minWidth / this.aspectRatio;
3186
			pMaxWidth = b.maxHeight * this.aspectRatio;
3187
			pMaxHeight = b.maxWidth / this.aspectRatio;
3188
3189
			if(pMinWidth > b.minWidth) {
3190
				b.minWidth = pMinWidth;
3191
			}
3192
			if(pMinHeight > b.minHeight) {
3193
				b.minHeight = pMinHeight;
3194
			}
3195
			if(pMaxWidth < b.maxWidth) {
3196
				b.maxWidth = pMaxWidth;
3197
			}
3198
			if(pMaxHeight < b.maxHeight) {
3199
				b.maxHeight = pMaxHeight;
3200
			}
3201
		}
3202
		this._vBoundaries = b;
3203
	},
3204
3205
	_updateCache: function(data) {
3206
		this.offset = this.helper.offset();
3207
		if (isNumber(data.left)) {
3208
			this.position.left = data.left;
3209
		}
3210
		if (isNumber(data.top)) {
3211
			this.position.top = data.top;
3212
		}
3213
		if (isNumber(data.height)) {
3214
			this.size.height = data.height;
3215
		}
3216
		if (isNumber(data.width)) {
3217
			this.size.width = data.width;
3218
		}
3219
	},
3220
3221
	_updateRatio: function( data ) {
3222
3223
		var cpos = this.position,
3224
			csize = this.size,
3225
			a = this.axis;
3226
3227
		if (isNumber(data.height)) {
3228
			data.width = (data.height * this.aspectRatio);
3229
		} else if (isNumber(data.width)) {
3230
			data.height = (data.width / this.aspectRatio);
3231
		}
3232
3233
		if (a === "sw") {
3234
			data.left = cpos.left + (csize.width - data.width);
3235
			data.top = null;
3236
		}
3237
		if (a === "nw") {
3238
			data.top = cpos.top + (csize.height - data.height);
3239
			data.left = cpos.left + (csize.width - data.width);
3240
		}
3241
3242
		return data;
3243
	},
3244
3245
	_respectSize: function( data ) {
3246
3247
		var o = this._vBoundaries,
3248
			a = this.axis,
3249
			ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
3250
			isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
3251
			dw = this.originalPosition.left + this.originalSize.width,
3252
			dh = this.position.top + this.size.height,
3253
			cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
3254
		if (isminw) {
3255
			data.width = o.minWidth;
3256
		}
3257
		if (isminh) {
3258
			data.height = o.minHeight;
3259
		}
3260
		if (ismaxw) {
3261
			data.width = o.maxWidth;
3262
		}
3263
		if (ismaxh) {
3264
			data.height = o.maxHeight;
3265
		}
3266
3267
		if (isminw && cw) {
3268
			data.left = dw - o.minWidth;
3269
		}
3270
		if (ismaxw && cw) {
3271
			data.left = dw - o.maxWidth;
3272
		}
3273
		if (isminh && ch) {
3274
			data.top = dh - o.minHeight;
3275
		}
3276
		if (ismaxh && ch) {
3277
			data.top = dh - o.maxHeight;
3278
		}
3279
3280
		// fixing jump error on top/left - bug #2330
3281
		if (!data.width && !data.height && !data.left && data.top) {
3282
			data.top = null;
3283
		} else if (!data.width && !data.height && !data.top && data.left) {
3284
			data.left = null;
3285
		}
3286
3287
		return data;
3288
	},
3289
3290
	_proportionallyResize: function() {
3291
3292
		if (!this._proportionallyResizeElements.length) {
3293
			return;
3294
		}
3295
3296
		var i, j, borders, paddings, prel,
3297
			element = this.helper || this.element;
3298
3299
		for ( i=0; i < this._proportionallyResizeElements.length; i++) {
3300
3301
			prel = this._proportionallyResizeElements[i];
3302
3303
			if (!this.borderDif) {
3304
				this.borderDif = [];
3305
				borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
3306
				paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
3307
3308
				for ( j = 0; j < borders.length; j++ ) {
3309
					this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
3310
				}
3311
			}
3312
3313
			prel.css({
3314
				height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
3315
				width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
3316
			});
3317
3318
		}
3319
3320
	},
3321
3322
	_renderProxy: function() {
3323
3324
		var el = this.element, o = this.options;
3325
		this.elementOffset = el.offset();
3326
3327
		if(this._helper) {
3328
3329
			this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
3330
3331
			this.helper.addClass(this._helper).css({
3332
				width: this.element.outerWidth() - 1,
3333
				height: this.element.outerHeight() - 1,
3334
				position: "absolute",
3335
				left: this.elementOffset.left +"px",
3336
				top: this.elementOffset.top +"px",
3337
				zIndex: ++o.zIndex //TODO: Don't modify option
3338
			});
3339
3340
			this.helper
3341
				.appendTo("body")
3342
				.disableSelection();
3343
3344
		} else {
3345
			this.helper = this.element;
3346
		}
3347
3348
	},
3349
3350
	_change: {
3351
		e: function(event, dx) {
3352
			return { width: this.originalSize.width + dx };
3353
		},
3354
		w: function(event, dx) {
3355
			var cs = this.originalSize, sp = this.originalPosition;
3356
			return { left: sp.left + dx, width: cs.width - dx };
3357
		},
3358
		n: function(event, dx, dy) {
3359
			var cs = this.originalSize, sp = this.originalPosition;
3360
			return { top: sp.top + dy, height: cs.height - dy };
3361
		},
3362
		s: function(event, dx, dy) {
3363
			return { height: this.originalSize.height + dy };
3364
		},
3365
		se: function(event, dx, dy) {
3366
			return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
3367
		},
3368
		sw: function(event, dx, dy) {
3369
			return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
3370
		},
3371
		ne: function(event, dx, dy) {
3372
			return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
3373
		},
3374
		nw: function(event, dx, dy) {
3375
			return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
3376
		}
3377
	},
3378
3379
	_propagate: function(n, event) {
3380
		$.ui.plugin.call(this, n, [event, this.ui()]);
3381
		(n !== "resize" && this._trigger(n, event, this.ui()));
3382
	},
3383
3384
	plugins: {},
3385
3386
	ui: function() {
3387
		return {
3388
			originalElement: this.originalElement,
3389
			element: this.element,
3390
			helper: this.helper,
3391
			position: this.position,
3392
			size: this.size,
3393
			originalSize: this.originalSize,
3394
			originalPosition: this.originalPosition
3395
		};
3396
	}
3397
3398
});
3399
3400
/*
3401
 * Resizable Extensions
3402
 */
3403
3404
$.ui.plugin.add("resizable", "animate", {
3405
3406
	stop: function( event ) {
3407
		var that = $(this).data("ui-resizable"),
3408
			o = that.options,
3409
			pr = that._proportionallyResizeElements,
3410
			ista = pr.length && (/textarea/i).test(pr[0].nodeName),
3411
			soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
3412
			soffsetw = ista ? 0 : that.sizeDiff.width,
3413
			style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
3414
			left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
3415
			top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
3416
3417
		that.element.animate(
3418
			$.extend(style, top && left ? { top: top, left: left } : {}), {
3419
				duration: o.animateDuration,
3420
				easing: o.animateEasing,
3421
				step: function() {
3422
3423
					var data = {
3424
						width: parseInt(that.element.css("width"), 10),
3425
						height: parseInt(that.element.css("height"), 10),
3426
						top: parseInt(that.element.css("top"), 10),
3427
						left: parseInt(that.element.css("left"), 10)
3428
					};
3429
3430
					if (pr && pr.length) {
3431
						$(pr[0]).css({ width: data.width, height: data.height });
3432
					}
3433
3434
					// propagating resize, and updating values for each animation step
3435
					that._updateCache(data);
3436
					that._propagate("resize", event);
3437
3438
				}
3439
			}
3440
		);
3441
	}
3442
3443
});
3444
3445
$.ui.plugin.add("resizable", "containment", {
3446
3447
	start: function() {
3448
		var element, p, co, ch, cw, width, height,
3449
			that = $(this).data("ui-resizable"),
3450
			o = that.options,
3451
			el = that.element,
3452
			oc = o.containment,
3453
			ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
3454
3455
		if (!ce) {
3456
			return;
3457
		}
3458
3459
		that.containerElement = $(ce);
3460
3461
		if (/document/.test(oc) || oc === document) {
3462
			that.containerOffset = { left: 0, top: 0 };
3463
			that.containerPosition = { left: 0, top: 0 };
3464
3465
			that.parentData = {
3466
				element: $(document), left: 0, top: 0,
3467
				width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
3468
			};
3469
		}
3470
3471
		// i'm a node, so compute top, left, right, bottom
3472
		else {
3473
			element = $(ce);
3474
			p = [];
3475
			$([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
3476
3477
			that.containerOffset = element.offset();
3478
			that.containerPosition = element.position();
3479
			that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
3480
3481
			co = that.containerOffset;
3482
			ch = that.containerSize.height;
3483
			cw = that.containerSize.width;
3484
			width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw );
3485
			height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
3486
3487
			that.parentData = {
3488
				element: ce, left: co.left, top: co.top, width: width, height: height
3489
			};
3490
		}
3491
	},
3492
3493
	resize: function( event ) {
3494
		var woset, hoset, isParent, isOffsetRelative,
3495
			that = $(this).data("ui-resizable"),
3496
			o = that.options,
3497
			co = that.containerOffset, cp = that.position,
3498
			pRatio = that._aspectRatio || event.shiftKey,
3499
			cop = { top:0, left:0 }, ce = that.containerElement;
3500
3501
		if (ce[0] !== document && (/static/).test(ce.css("position"))) {
3502
			cop = co;
3503
		}
3504
3505
		if (cp.left < (that._helper ? co.left : 0)) {
3506
			that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left));
3507
			if (pRatio) {
3508
				that.size.height = that.size.width / that.aspectRatio;
3509
			}
3510
			that.position.left = o.helper ? co.left : 0;
3511
		}
3512
3513
		if (cp.top < (that._helper ? co.top : 0)) {
3514
			that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top);
3515
			if (pRatio) {
3516
				that.size.width = that.size.height * that.aspectRatio;
3517
			}
3518
			that.position.top = that._helper ? co.top : 0;
3519
		}
3520
3521
		that.offset.left = that.parentData.left+that.position.left;
3522
		that.offset.top = that.parentData.top+that.position.top;
3523
3524
		woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width );
3525
		hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height );
3526
3527
		isParent = that.containerElement.get(0) === that.element.parent().get(0);
3528
		isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position"));
3529
3530
		if(isParent && isOffsetRelative) {
3531
			woset -= that.parentData.left;
3532
		}
3533
3534
		if (woset + that.size.width >= that.parentData.width) {
3535
			that.size.width = that.parentData.width - woset;
3536
			if (pRatio) {
3537
				that.size.height = that.size.width / that.aspectRatio;
3538
			}
3539
		}
3540
3541
		if (hoset + that.size.height >= that.parentData.height) {
3542
			that.size.height = that.parentData.height - hoset;
3543
			if (pRatio) {
3544
				that.size.width = that.size.height * that.aspectRatio;
3545
			}
3546
		}
3547
	},
3548
3549
	stop: function(){
3550
		var that = $(this).data("ui-resizable"),
3551
			o = that.options,
3552
			co = that.containerOffset,
3553
			cop = that.containerPosition,
3554
			ce = that.containerElement,
3555
			helper = $(that.helper),
3556
			ho = helper.offset(),
3557
			w = helper.outerWidth() - that.sizeDiff.width,
3558
			h = helper.outerHeight() - that.sizeDiff.height;
3559
3560
		if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) {
3561
			$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3562
		}
3563
3564
		if (that._helper && !o.animate && (/static/).test(ce.css("position"))) {
3565
			$(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
3566
		}
3567
3568
	}
3569
});
3570
3571
$.ui.plugin.add("resizable", "alsoResize", {
3572
3573
	start: function () {
3574
		var that = $(this).data("ui-resizable"),
3575
			o = that.options,
3576
			_store = function (exp) {
3577
				$(exp).each(function() {
3578
					var el = $(this);
3579
					el.data("ui-resizable-alsoresize", {
3580
						width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
3581
						left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
3582
					});
3583
				});
3584
			};
3585
3586
		if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
3587
			if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
3588
			else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
3589
		}else{
3590
			_store(o.alsoResize);
3591
		}
3592
	},
3593
3594
	resize: function (event, ui) {
3595
		var that = $(this).data("ui-resizable"),
3596
			o = that.options,
3597
			os = that.originalSize,
3598
			op = that.originalPosition,
3599
			delta = {
3600
				height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
3601
				top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
3602
			},
3603
3604
			_alsoResize = function (exp, c) {
3605
				$(exp).each(function() {
3606
					var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
3607
						css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
3608
3609
					$.each(css, function (i, prop) {
3610
						var sum = (start[prop]||0) + (delta[prop]||0);
3611
						if (sum && sum >= 0) {
3612
							style[prop] = sum || null;
3613
						}
3614
					});
3615
3616
					el.css(style);
3617
				});
3618
			};
3619
3620
		if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
3621
			$.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
3622
		}else{
3623
			_alsoResize(o.alsoResize);
3624
		}
3625
	},
3626
3627
	stop: function () {
3628
		$(this).removeData("resizable-alsoresize");
3629
	}
3630
});
3631
3632
$.ui.plugin.add("resizable", "ghost", {
3633
3634
	start: function() {
3635
3636
		var that = $(this).data("ui-resizable"), o = that.options, cs = that.size;
3637
3638
		that.ghost = that.originalElement.clone();
3639
		that.ghost
3640
			.css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
3641
			.addClass("ui-resizable-ghost")
3642
			.addClass(typeof o.ghost === "string" ? o.ghost : "");
3643
3644
		that.ghost.appendTo(that.helper);
3645
3646
	},
3647
3648
	resize: function(){
3649
		var that = $(this).data("ui-resizable");
3650
		if (that.ghost) {
3651
			that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
3652
		}
3653
	},
3654
3655
	stop: function() {
3656
		var that = $(this).data("ui-resizable");
3657
		if (that.ghost && that.helper) {
3658
			that.helper.get(0).removeChild(that.ghost.get(0));
3659
		}
3660
	}
3661
3662
});
3663
3664
$.ui.plugin.add("resizable", "grid", {
3665
3666
	resize: function() {
3667
		var that = $(this).data("ui-resizable"),
3668
			o = that.options,
3669
			cs = that.size,
3670
			os = that.originalSize,
3671
			op = that.originalPosition,
3672
			a = that.axis,
3673
			grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
3674
			gridX = (grid[0]||1),
3675
			gridY = (grid[1]||1),
3676
			ox = Math.round((cs.width - os.width) / gridX) * gridX,
3677
			oy = Math.round((cs.height - os.height) / gridY) * gridY,
3678
			newWidth = os.width + ox,
3679
			newHeight = os.height + oy,
3680
			isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
3681
			isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
3682
			isMinWidth = o.minWidth && (o.minWidth > newWidth),
3683
			isMinHeight = o.minHeight && (o.minHeight > newHeight);
3684
3685
		o.grid = grid;
3686
3687
		if (isMinWidth) {
3688
			newWidth = newWidth + gridX;
3689
		}
3690
		if (isMinHeight) {
3691
			newHeight = newHeight + gridY;
3692
		}
3693
		if (isMaxWidth) {
3694
			newWidth = newWidth - gridX;
3695
		}
3696
		if (isMaxHeight) {
3697
			newHeight = newHeight - gridY;
3698
		}
3699
3700
		if (/^(se|s|e)$/.test(a)) {
3701
			that.size.width = newWidth;
3702
			that.size.height = newHeight;
3703
		} else if (/^(ne)$/.test(a)) {
3704
			that.size.width = newWidth;
3705
			that.size.height = newHeight;
3706
			that.position.top = op.top - oy;
3707
		} else if (/^(sw)$/.test(a)) {
3708
			that.size.width = newWidth;
3709
			that.size.height = newHeight;
3710
			that.position.left = op.left - ox;
3711
		} else {
3712
			that.size.width = newWidth;
3713
			that.size.height = newHeight;
3714
			that.position.top = op.top - oy;
3715
			that.position.left = op.left - ox;
3716
		}
3717
	}
3718
3719
});
3720
3721
})(jQuery);
3722
(function( $, undefined ) {
3723
3724
$.widget("ui.selectable", $.ui.mouse, {
3725
	version: "1.10.3",
3726
	options: {
3727
		appendTo: "body",
3728
		autoRefresh: true,
3729
		distance: 0,
3730
		filter: "*",
3731
		tolerance: "touch",
3732
3733
		// callbacks
3734
		selected: null,
3735
		selecting: null,
3736
		start: null,
3737
		stop: null,
3738
		unselected: null,
3739
		unselecting: null
3740
	},
3741
	_create: function() {
3742
		var selectees,
3743
			that = this;
3744
3745
		this.element.addClass("ui-selectable");
3746
3747
		this.dragged = false;
3748
3749
		// cache selectee children based on filter
3750
		this.refresh = function() {
3751
			selectees = $(that.options.filter, that.element[0]);
3752
			selectees.addClass("ui-selectee");
3753
			selectees.each(function() {
3754
				var $this = $(this),
3755
					pos = $this.offset();
3756
				$.data(this, "selectable-item", {
3757
					element: this,
3758
					$element: $this,
3759
					left: pos.left,
3760
					top: pos.top,
3761
					right: pos.left + $this.outerWidth(),
3762
					bottom: pos.top + $this.outerHeight(),
3763
					startselected: false,
3764
					selected: $this.hasClass("ui-selected"),
3765
					selecting: $this.hasClass("ui-selecting"),
3766
					unselecting: $this.hasClass("ui-unselecting")
3767
				});
3768
			});
3769
		};
3770
		this.refresh();
3771
3772
		this.selectees = selectees.addClass("ui-selectee");
3773
3774
		this._mouseInit();
3775
3776
		this.helper = $("<div class='ui-selectable-helper'></div>");
3777
	},
3778
3779
	_destroy: function() {
3780
		this.selectees
3781
			.removeClass("ui-selectee")
3782
			.removeData("selectable-item");
3783
		this.element
3784
			.removeClass("ui-selectable ui-selectable-disabled");
3785
		this._mouseDestroy();
3786
	},
3787
3788
	_mouseStart: function(event) {
3789
		var that = this,
3790
			options = this.options;
3791
3792
		this.opos = [event.pageX, event.pageY];
3793
3794
		if (this.options.disabled) {
3795
			return;
3796
		}
3797
3798
		this.selectees = $(options.filter, this.element[0]);
3799
3800
		this._trigger("start", event);
3801
3802
		$(options.appendTo).append(this.helper);
3803
		// position helper (lasso)
3804
		this.helper.css({
3805
			"left": event.pageX,
3806
			"top": event.pageY,
3807
			"width": 0,
3808
			"height": 0
3809
		});
3810
3811
		if (options.autoRefresh) {
3812
			this.refresh();
3813
		}
3814
3815
		this.selectees.filter(".ui-selected").each(function() {
3816
			var selectee = $.data(this, "selectable-item");
3817
			selectee.startselected = true;
3818
			if (!event.metaKey && !event.ctrlKey) {
3819
				selectee.$element.removeClass("ui-selected");
3820
				selectee.selected = false;
3821
				selectee.$element.addClass("ui-unselecting");
3822
				selectee.unselecting = true;
3823
				// selectable UNSELECTING callback
3824
				that._trigger("unselecting", event, {
3825
					unselecting: selectee.element
3826
				});
3827
			}
3828
		});
3829
3830
		$(event.target).parents().addBack().each(function() {
3831
			var doSelect,
3832
				selectee = $.data(this, "selectable-item");
3833
			if (selectee) {
3834
				doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
3835
				selectee.$element
3836
					.removeClass(doSelect ? "ui-unselecting" : "ui-selected")
3837
					.addClass(doSelect ? "ui-selecting" : "ui-unselecting");
3838
				selectee.unselecting = !doSelect;
3839
				selectee.selecting = doSelect;
3840
				selectee.selected = doSelect;
3841
				// selectable (UN)SELECTING callback
3842
				if (doSelect) {
3843
					that._trigger("selecting", event, {
3844
						selecting: selectee.element
3845
					});
3846
				} else {
3847
					that._trigger("unselecting", event, {
3848
						unselecting: selectee.element
3849
					});
3850
				}
3851
				return false;
3852
			}
3853
		});
3854
3855
	},
3856
3857
	_mouseDrag: function(event) {
3858
3859
		this.dragged = true;
3860
3861
		if (this.options.disabled) {
3862
			return;
3863
		}
3864
3865
		var tmp,
3866
			that = this,
3867
			options = this.options,
3868
			x1 = this.opos[0],
3869
			y1 = this.opos[1],
3870
			x2 = event.pageX,
3871
			y2 = event.pageY;
3872
3873
		if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
3874
		if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
3875
		this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
3876
3877
		this.selectees.each(function() {
3878
			var selectee = $.data(this, "selectable-item"),
3879
				hit = false;
3880
3881
			//prevent helper from being selected if appendTo: selectable
3882
			if (!selectee || selectee.element === that.element[0]) {
3883
				return;
3884
			}
3885
3886
			if (options.tolerance === "touch") {
3887
				hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
3888
			} else if (options.tolerance === "fit") {
3889
				hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
3890
			}
3891
3892
			if (hit) {
3893
				// SELECT
3894
				if (selectee.selected) {
3895
					selectee.$element.removeClass("ui-selected");
3896
					selectee.selected = false;
3897
				}
3898
				if (selectee.unselecting) {
3899
					selectee.$element.removeClass("ui-unselecting");
3900
					selectee.unselecting = false;
3901
				}
3902
				if (!selectee.selecting) {
3903
					selectee.$element.addClass("ui-selecting");
3904
					selectee.selecting = true;
3905
					// selectable SELECTING callback
3906
					that._trigger("selecting", event, {
3907
						selecting: selectee.element
3908
					});
3909
				}
3910
			} else {
3911
				// UNSELECT
3912
				if (selectee.selecting) {
3913
					if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
3914
						selectee.$element.removeClass("ui-selecting");
3915
						selectee.selecting = false;
3916
						selectee.$element.addClass("ui-selected");
3917
						selectee.selected = true;
3918
					} else {
3919
						selectee.$element.removeClass("ui-selecting");
3920
						selectee.selecting = false;
3921
						if (selectee.startselected) {
3922
							selectee.$element.addClass("ui-unselecting");
3923
							selectee.unselecting = true;
3924
						}
3925
						// selectable UNSELECTING callback
3926
						that._trigger("unselecting", event, {
3927
							unselecting: selectee.element
3928
						});
3929
					}
3930
				}
3931
				if (selectee.selected) {
3932
					if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
3933
						selectee.$element.removeClass("ui-selected");
3934
						selectee.selected = false;
3935
3936
						selectee.$element.addClass("ui-unselecting");
3937
						selectee.unselecting = true;
3938
						// selectable UNSELECTING callback
3939
						that._trigger("unselecting", event, {
3940
							unselecting: selectee.element
3941
						});
3942
					}
3943
				}
3944
			}
3945
		});
3946
3947
		return false;
3948
	},
3949
3950
	_mouseStop: function(event) {
3951
		var that = this;
3952
3953
		this.dragged = false;
3954
3955
		$(".ui-unselecting", this.element[0]).each(function() {
3956
			var selectee = $.data(this, "selectable-item");
3957
			selectee.$element.removeClass("ui-unselecting");
3958
			selectee.unselecting = false;
3959
			selectee.startselected = false;
3960
			that._trigger("unselected", event, {
3961
				unselected: selectee.element
3962
			});
3963
		});
3964
		$(".ui-selecting", this.element[0]).each(function() {
3965
			var selectee = $.data(this, "selectable-item");
3966
			selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
3967
			selectee.selecting = false;
3968
			selectee.selected = true;
3969
			selectee.startselected = true;
3970
			that._trigger("selected", event, {
3971
				selected: selectee.element
3972
			});
3973
		});
3974
		this._trigger("stop", event);
3975
3976
		this.helper.remove();
3977
3978
		return false;
3979
	}
3980
3981
});
3982
3983
})(jQuery);
3984
(function( $, undefined ) {
3985
3986
/*jshint loopfunc: true */
3987
3988
function isOverAxis( x, reference, size ) {
3989
	return ( x > reference ) && ( x < ( reference + size ) );
3990
}
3991
3992
function isFloating(item) {
3993
	return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
3994
}
3995
3996
$.widget("ui.sortable", $.ui.mouse, {
3997
	version: "1.10.3",
3998
	widgetEventPrefix: "sort",
3999
	ready: false,
4000
	options: {
4001
		appendTo: "parent",
4002
		axis: false,
4003
		connectWith: false,
4004
		containment: false,
4005
		cursor: "auto",
4006
		cursorAt: false,
4007
		dropOnEmpty: true,
4008
		forcePlaceholderSize: false,
4009
		forceHelperSize: false,
4010
		grid: false,
4011
		handle: false,
4012
		helper: "original",
4013
		items: "> *",
4014
		opacity: false,
4015
		placeholder: false,
4016
		revert: false,
4017
		scroll: true,
4018
		scrollSensitivity: 20,
4019
		scrollSpeed: 20,
4020
		scope: "default",
4021
		tolerance: "intersect",
4022
		zIndex: 1000,
4023
4024
		// callbacks
4025
		activate: null,
4026
		beforeStop: null,
4027
		change: null,
4028
		deactivate: null,
4029
		out: null,
4030
		over: null,
4031
		receive: null,
4032
		remove: null,
4033
		sort: null,
4034
		start: null,
4035
		stop: null,
4036
		update: null
4037
	},
4038
	_create: function() {
4039
4040
		var o = this.options;
4041
		this.containerCache = {};
4042
		this.element.addClass("ui-sortable");
4043
4044
		//Get the items
4045
		this.refresh();
4046
4047
		//Let's determine if the items are being displayed horizontally
4048
		this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false;
4049
4050
		//Let's determine the parent's offset
4051
		this.offset = this.element.offset();
4052
4053
		//Initialize mouse events for interaction
4054
		this._mouseInit();
4055
4056
		//We're ready to go
4057
		this.ready = true;
4058
4059
	},
4060
4061
	_destroy: function() {
4062
		this.element
4063
			.removeClass("ui-sortable ui-sortable-disabled");
4064
		this._mouseDestroy();
4065
4066
		for ( var i = this.items.length - 1; i >= 0; i-- ) {
4067
			this.items[i].item.removeData(this.widgetName + "-item");
4068
		}
4069
4070
		return this;
4071
	},
4072
4073
	_setOption: function(key, value){
4074
		if ( key === "disabled" ) {
4075
			this.options[ key ] = value;
4076
4077
			this.widget().toggleClass( "ui-sortable-disabled", !!value );
4078
		} else {
4079
			// Don't call widget base _setOption for disable as it adds ui-state-disabled class
4080
			$.Widget.prototype._setOption.apply(this, arguments);
4081
		}
4082
	},
4083
4084
	_mouseCapture: function(event, overrideHandle) {
4085
		var currentItem = null,
4086
			validHandle = false,
4087
			that = this;
4088
4089
		if (this.reverting) {
4090
			return false;
4091
		}
4092
4093
		if(this.options.disabled || this.options.type === "static") {
4094
			return false;
4095
		}
4096
4097
		//We have to refresh the items data once first
4098
		this._refreshItems(event);
4099
4100
		//Find out if the clicked node (or one of its parents) is a actual item in this.items
4101
		$(event.target).parents().each(function() {
4102
			if($.data(this, that.widgetName + "-item") === that) {
4103
				currentItem = $(this);
4104
				return false;
4105
			}
4106
		});
4107
		if($.data(event.target, that.widgetName + "-item") === that) {
4108
			currentItem = $(event.target);
4109
		}
4110
4111
		if(!currentItem) {
4112
			return false;
4113
		}
4114
		if(this.options.handle && !overrideHandle) {
4115
			$(this.options.handle, currentItem).find("*").addBack().each(function() {
4116
				if(this === event.target) {
4117
					validHandle = true;
4118
				}
4119
			});
4120
			if(!validHandle) {
4121
				return false;
4122
			}
4123
		}
4124
4125
		this.currentItem = currentItem;
4126
		this._removeCurrentsFromItems();
4127
		return true;
4128
4129
	},
4130
4131
	_mouseStart: function(event, overrideHandle, noActivation) {
4132
4133
		var i, body,
4134
			o = this.options;
4135
4136
		this.currentContainer = this;
4137
4138
		//We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
4139
		this.refreshPositions();
4140
4141
		//Create and append the visible helper
4142
		this.helper = this._createHelper(event);
4143
4144
		//Cache the helper size
4145
		this._cacheHelperProportions();
4146
4147
		/*
4148
		 * - Position generation -
4149
		 * This block generates everything position related - it's the core of draggables.
4150
		 */
4151
4152
		//Cache the margins of the original element
4153
		this._cacheMargins();
4154
4155
		//Get the next scrolling parent
4156
		this.scrollParent = this.helper.scrollParent();
4157
4158
		//The element's absolute position on the page minus margins
4159
		this.offset = this.currentItem.offset();
4160
		this.offset = {
4161
			top: this.offset.top - this.margins.top,
4162
			left: this.offset.left - this.margins.left
4163
		};
4164
4165
		$.extend(this.offset, {
4166
			click: { //Where the click happened, relative to the element
4167
				left: event.pageX - this.offset.left,
4168
				top: event.pageY - this.offset.top
4169
			},
4170
			parent: this._getParentOffset(),
4171
			relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
4172
		});
4173
4174
		// Only after we got the offset, we can change the helper's position to absolute
4175
		// TODO: Still need to figure out a way to make relative sorting possible
4176
		this.helper.css("position", "absolute");
4177
		this.cssPosition = this.helper.css("position");
4178
4179
		//Generate the original position
4180
		this.originalPosition = this._generatePosition(event);
4181
		this.originalPageX = event.pageX;
4182
		this.originalPageY = event.pageY;
4183
4184
		//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
4185
		(o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
4186
4187
		//Cache the former DOM position
4188
		this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
4189
4190
		//If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
4191
		if(this.helper[0] !== this.currentItem[0]) {
4192
			this.currentItem.hide();
4193
		}
4194
4195
		//Create the placeholder
4196
		this._createPlaceholder();
4197
4198
		//Set a containment if given in the options
4199
		if(o.containment) {
4200
			this._setContainment();
4201
		}
4202
4203
		if( o.cursor && o.cursor !== "auto" ) { // cursor option
4204
			body = this.document.find( "body" );
4205
4206
			// support: IE
4207
			this.storedCursor = body.css( "cursor" );
4208
			body.css( "cursor", o.cursor );
4209
4210
			this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
4211
		}
4212
4213
		if(o.opacity) { // opacity option
4214
			if (this.helper.css("opacity")) {
4215
				this._storedOpacity = this.helper.css("opacity");
4216
			}
4217
			this.helper.css("opacity", o.opacity);
4218
		}
4219
4220
		if(o.zIndex) { // zIndex option
4221
			if (this.helper.css("zIndex")) {
4222
				this._storedZIndex = this.helper.css("zIndex");
4223
			}
4224
			this.helper.css("zIndex", o.zIndex);
4225
		}
4226
4227
		//Prepare scrolling
4228
		if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
4229
			this.overflowOffset = this.scrollParent.offset();
4230
		}
4231
4232
		//Call callbacks
4233
		this._trigger("start", event, this._uiHash());
4234
4235
		//Recache the helper size
4236
		if(!this._preserveHelperProportions) {
4237
			this._cacheHelperProportions();
4238
		}
4239
4240
4241
		//Post "activate" events to possible containers
4242
		if( !noActivation ) {
4243
			for ( i = this.containers.length - 1; i >= 0; i-- ) {
4244
				this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
4245
			}
4246
		}
4247
4248
		//Prepare possible droppables
4249
		if($.ui.ddmanager) {
4250
			$.ui.ddmanager.current = this;
4251
		}
4252
4253
		if ($.ui.ddmanager && !o.dropBehaviour) {
4254
			$.ui.ddmanager.prepareOffsets(this, event);
4255
		}
4256
4257
		this.dragging = true;
4258
4259
		this.helper.addClass("ui-sortable-helper");
4260
		this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
4261
		return true;
4262
4263
	},
4264
4265
	_mouseDrag: function(event) {
4266
		var i, item, itemElement, intersection,
4267
			o = this.options,
4268
			scrolled = false;
4269
4270
		//Compute the helpers position
4271
		this.position = this._generatePosition(event);
4272
		this.positionAbs = this._convertPositionTo("absolute");
4273
4274
		if (!this.lastPositionAbs) {
4275
			this.lastPositionAbs = this.positionAbs;
4276
		}
4277
4278
		//Do scrolling
4279
		if(this.options.scroll) {
4280
			if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
4281
4282
				if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
4283
					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
4284
				} else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
4285
					this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
4286
				}
4287
4288
				if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
4289
					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
4290
				} else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
4291
					this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
4292
				}
4293
4294
			} else {
4295
4296
				if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
4297
					scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
4298
				} else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
4299
					scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
4300
				}
4301
4302
				if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
4303
					scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
4304
				} else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
4305
					scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
4306
				}
4307
4308
			}
4309
4310
			if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
4311
				$.ui.ddmanager.prepareOffsets(this, event);
4312
			}
4313
		}
4314
4315
		//Regenerate the absolute position used for position checks
4316
		this.positionAbs = this._convertPositionTo("absolute");
4317
4318
		//Set the helper position
4319
		if(!this.options.axis || this.options.axis !== "y") {
4320
			this.helper[0].style.left = this.position.left+"px";
4321
		}
4322
		if(!this.options.axis || this.options.axis !== "x") {
4323
			this.helper[0].style.top = this.position.top+"px";
4324
		}
4325
4326
		//Rearrange
4327
		for (i = this.items.length - 1; i >= 0; i--) {
4328
4329
			//Cache variables and intersection, continue if no intersection
4330
			item = this.items[i];
4331
			itemElement = item.item[0];
4332
			intersection = this._intersectsWithPointer(item);
4333
			if (!intersection) {
4334
				continue;
4335
			}
4336
4337
			// Only put the placeholder inside the current Container, skip all
4338
			// items form other containers. This works because when moving
4339
			// an item from one container to another the
4340
			// currentContainer is switched before the placeholder is moved.
4341
			//
4342
			// Without this moving items in "sub-sortables" can cause the placeholder to jitter
4343
			// beetween the outer and inner container.
4344
			if (item.instance !== this.currentContainer) {
4345
				continue;
4346
			}
4347
4348
			// cannot intersect with itself
4349
			// no useless actions that have been done before
4350
			// no action if the item moved is the parent of the item checked
4351
			if (itemElement !== this.currentItem[0] &&
4352
				this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
4353
				!$.contains(this.placeholder[0], itemElement) &&
4354
				(this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
4355
			) {
4356
4357
				this.direction = intersection === 1 ? "down" : "up";
4358
4359
				if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
4360
					this._rearrange(event, item);
4361
				} else {
4362
					break;
4363
				}
4364
4365
				this._trigger("change", event, this._uiHash());
4366
				break;
4367
			}
4368
		}
4369
4370
		//Post events to containers
4371
		this._contactContainers(event);
4372
4373
		//Interconnect with droppables
4374
		if($.ui.ddmanager) {
4375
			$.ui.ddmanager.drag(this, event);
4376
		}
4377
4378
		//Call callbacks
4379
		this._trigger("sort", event, this._uiHash());
4380
4381
		this.lastPositionAbs = this.positionAbs;
4382
		return false;
4383
4384
	},
4385
4386
	_mouseStop: function(event, noPropagation) {
4387
4388
		if(!event) {
4389
			return;
4390
		}
4391
4392
		//If we are using droppables, inform the manager about the drop
4393
		if ($.ui.ddmanager && !this.options.dropBehaviour) {
4394
			$.ui.ddmanager.drop(this, event);
4395
		}
4396
4397
		if(this.options.revert) {
4398
			var that = this,
4399
				cur = this.placeholder.offset(),
4400
				axis = this.options.axis,
4401
				animation = {};
4402
4403
			if ( !axis || axis === "x" ) {
4404
				animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
4405
			}
4406
			if ( !axis || axis === "y" ) {
4407
				animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
4408
			}
4409
			this.reverting = true;
4410
			$(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
4411
				that._clear(event);
4412
			});
4413
		} else {
4414
			this._clear(event, noPropagation);
4415
		}
4416
4417
		return false;
4418
4419
	},
4420
4421
	cancel: function() {
4422
4423
		if(this.dragging) {
4424
4425
			this._mouseUp({ target: null });
4426
4427
			if(this.options.helper === "original") {
4428
				this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
4429
			} else {
4430
				this.currentItem.show();
4431
			}
4432
4433
			//Post deactivating events to containers
4434
			for (var i = this.containers.length - 1; i >= 0; i--){
4435
				this.containers[i]._trigger("deactivate", null, this._uiHash(this));
4436
				if(this.containers[i].containerCache.over) {
4437
					this.containers[i]._trigger("out", null, this._uiHash(this));
4438
					this.containers[i].containerCache.over = 0;
4439
				}
4440
			}
4441
4442
		}
4443
4444
		if (this.placeholder) {
4445
			//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
4446
			if(this.placeholder[0].parentNode) {
4447
				this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
4448
			}
4449
			if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
4450
				this.helper.remove();
4451
			}
4452
4453
			$.extend(this, {
4454
				helper: null,
4455
				dragging: false,
4456
				reverting: false,
4457
				_noFinalSort: null
4458
			});
4459
4460
			if(this.domPosition.prev) {
4461
				$(this.domPosition.prev).after(this.currentItem);
4462
			} else {
4463
				$(this.domPosition.parent).prepend(this.currentItem);
4464
			}
4465
		}
4466
4467
		return this;
4468
4469
	},
4470
4471
	serialize: function(o) {
4472
4473
		var items = this._getItemsAsjQuery(o && o.connected),
4474
			str = [];
4475
		o = o || {};
4476
4477
		$(items).each(function() {
4478
			var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
4479
			if (res) {
4480
				str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
4481
			}
4482
		});
4483
4484
		if(!str.length && o.key) {
4485
			str.push(o.key + "=");
4486
		}
4487
4488
		return str.join("&");
4489
4490
	},
4491
4492
	toArray: function(o) {
4493
4494
		var items = this._getItemsAsjQuery(o && o.connected),
4495
			ret = [];
4496
4497
		o = o || {};
4498
4499
		items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
4500
		return ret;
4501
4502
	},
4503
4504
	/* Be careful with the following core functions */
4505
	_intersectsWith: function(item) {
4506
4507
		var x1 = this.positionAbs.left,
4508
			x2 = x1 + this.helperProportions.width,
4509
			y1 = this.positionAbs.top,
4510
			y2 = y1 + this.helperProportions.height,
4511
			l = item.left,
4512
			r = l + item.width,
4513
			t = item.top,
4514
			b = t + item.height,
4515
			dyClick = this.offset.click.top,
4516
			dxClick = this.offset.click.left,
4517
			isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
4518
			isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
4519
			isOverElement = isOverElementHeight && isOverElementWidth;
4520
4521
		if ( this.options.tolerance === "pointer" ||
4522
			this.options.forcePointerForContainers ||
4523
			(this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
4524
		) {
4525
			return isOverElement;
4526
		} else {
4527
4528
			return (l < x1 + (this.helperProportions.width / 2) && // Right Half
4529
				x2 - (this.helperProportions.width / 2) < r && // Left Half
4530
				t < y1 + (this.helperProportions.height / 2) && // Bottom Half
4531
				y2 - (this.helperProportions.height / 2) < b ); // Top Half
4532
4533
		}
4534
	},
4535
4536
	_intersectsWithPointer: function(item) {
4537
4538
		var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
4539
			isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
4540
			isOverElement = isOverElementHeight && isOverElementWidth,
4541
			verticalDirection = this._getDragVerticalDirection(),
4542
			horizontalDirection = this._getDragHorizontalDirection();
4543
4544
		if (!isOverElement) {
4545
			return false;
4546
		}
4547
4548
		return this.floating ?
4549
			( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
4550
			: ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
4551
4552
	},
4553
4554
	_intersectsWithSides: function(item) {
4555
4556
		var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
4557
			isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
4558
			verticalDirection = this._getDragVerticalDirection(),
4559
			horizontalDirection = this._getDragHorizontalDirection();
4560
4561
		if (this.floating && horizontalDirection) {
4562
			return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
4563
		} else {
4564
			return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
4565
		}
4566
4567
	},
4568
4569
	_getDragVerticalDirection: function() {
4570
		var delta = this.positionAbs.top - this.lastPositionAbs.top;
4571
		return delta !== 0 && (delta > 0 ? "down" : "up");
4572
	},
4573
4574
	_getDragHorizontalDirection: function() {
4575
		var delta = this.positionAbs.left - this.lastPositionAbs.left;
4576
		return delta !== 0 && (delta > 0 ? "right" : "left");
4577
	},
4578
4579
	refresh: function(event) {
4580
		this._refreshItems(event);
4581
		this.refreshPositions();
4582
		return this;
4583
	},
4584
4585
	_connectWith: function() {
4586
		var options = this.options;
4587
		return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
4588
	},
4589
4590
	_getItemsAsjQuery: function(connected) {
4591
4592
		var i, j, cur, inst,
4593
			items = [],
4594
			queries = [],
4595
			connectWith = this._connectWith();
4596
4597
		if(connectWith && connected) {
4598
			for (i = connectWith.length - 1; i >= 0; i--){
4599
				cur = $(connectWith[i]);
4600
				for ( j = cur.length - 1; j >= 0; j--){
4601
					inst = $.data(cur[j], this.widgetFullName);
4602
					if(inst && inst !== this && !inst.options.disabled) {
4603
						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
4604
					}
4605
				}
4606
			}
4607
		}
4608
4609
		queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
4610
4611
		for (i = queries.length - 1; i >= 0; i--){
4612
			queries[i][0].each(function() {
4613
				items.push(this);
4614
			});
4615
		}
4616
4617
		return $(items);
4618
4619
	},
4620
4621
	_removeCurrentsFromItems: function() {
4622
4623
		var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
4624
4625
		this.items = $.grep(this.items, function (item) {
4626
			for (var j=0; j < list.length; j++) {
4627
				if(list[j] === item.item[0]) {
4628
					return false;
4629
				}
4630
			}
4631
			return true;
4632
		});
4633
4634
	},
4635
4636
	_refreshItems: function(event) {
4637
4638
		this.items = [];
4639
		this.containers = [this];
4640
4641
		var i, j, cur, inst, targetData, _queries, item, queriesLength,
4642
			items = this.items,
4643
			queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
4644
			connectWith = this._connectWith();
4645
4646
		if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
4647
			for (i = connectWith.length - 1; i >= 0; i--){
4648
				cur = $(connectWith[i]);
4649
				for (j = cur.length - 1; j >= 0; j--){
4650
					inst = $.data(cur[j], this.widgetFullName);
4651
					if(inst && inst !== this && !inst.options.disabled) {
4652
						queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
4653
						this.containers.push(inst);
4654
					}
4655
				}
4656
			}
4657
		}
4658
4659
		for (i = queries.length - 1; i >= 0; i--) {
4660
			targetData = queries[i][1];
4661
			_queries = queries[i][0];
4662
4663
			for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
4664
				item = $(_queries[j]);
4665
4666
				item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
4667
4668
				items.push({
4669
					item: item,
4670
					instance: targetData,
4671
					width: 0, height: 0,
4672
					left: 0, top: 0
4673
				});
4674
			}
4675
		}
4676
4677
	},
4678
4679
	refreshPositions: function(fast) {
4680
4681
		//This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
4682
		if(this.offsetParent && this.helper) {
4683
			this.offset.parent = this._getParentOffset();
4684
		}
4685
4686
		var i, item, t, p;
4687
4688
		for (i = this.items.length - 1; i >= 0; i--){
4689
			item = this.items[i];
4690
4691
			//We ignore calculating positions of all connected containers when we're not over them
4692
			if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
4693
				continue;
4694
			}
4695
4696
			t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
4697
4698
			if (!fast) {
4699
				item.width = t.outerWidth();
4700
				item.height = t.outerHeight();
4701
			}
4702
4703
			p = t.offset();
4704
			item.left = p.left;
4705
			item.top = p.top;
4706
		}
4707
4708
		if(this.options.custom && this.options.custom.refreshContainers) {
4709
			this.options.custom.refreshContainers.call(this);
4710
		} else {
4711
			for (i = this.containers.length - 1; i >= 0; i--){
4712
				p = this.containers[i].element.offset();
4713
				this.containers[i].containerCache.left = p.left;
4714
				this.containers[i].containerCache.top = p.top;
4715
				this.containers[i].containerCache.width	= this.containers[i].element.outerWidth();
4716
				this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
4717
			}
4718
		}
4719
4720
		return this;
4721
	},
4722
4723
	_createPlaceholder: function(that) {
4724
		that = that || this;
4725
		var className,
4726
			o = that.options;
4727
4728
		if(!o.placeholder || o.placeholder.constructor === String) {
4729
			className = o.placeholder;
4730
			o.placeholder = {
4731
				element: function() {
4732
4733
					var nodeName = that.currentItem[0].nodeName.toLowerCase(),
4734
						element = $( "<" + nodeName + ">", that.document[0] )
4735
							.addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
4736
							.removeClass("ui-sortable-helper");
4737
4738
					if ( nodeName === "tr" ) {
4739
						that.currentItem.children().each(function() {
4740
							$( "<td>&#160;</td>", that.document[0] )
4741
								.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
4742
								.appendTo( element );
4743
						});
4744
					} else if ( nodeName === "img" ) {
4745
						element.attr( "src", that.currentItem.attr( "src" ) );
4746
					}
4747
4748
					if ( !className ) {
4749
						element.css( "visibility", "hidden" );
4750
					}
4751
4752
					return element;
4753
				},
4754
				update: function(container, p) {
4755
4756
					// 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
4757
					// 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
4758
					if(className && !o.forcePlaceholderSize) {
4759
						return;
4760
					}
4761
4762
					//If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
4763
					if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
4764
					if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
4765
				}
4766
			};
4767
		}
4768
4769
		//Create the placeholder
4770
		that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
4771
4772
		//Append it after the actual current item
4773
		that.currentItem.after(that.placeholder);
4774
4775
		//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
4776
		o.placeholder.update(that, that.placeholder);
4777
4778
	},
4779
4780
	_contactContainers: function(event) {
4781
		var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating,
4782
			innermostContainer = null,
4783
			innermostIndex = null;
4784
4785
		// get innermost container that intersects with item
4786
		for (i = this.containers.length - 1; i >= 0; i--) {
4787
4788
			// never consider a container that's located within the item itself
4789
			if($.contains(this.currentItem[0], this.containers[i].element[0])) {
4790
				continue;
4791
			}
4792
4793
			if(this._intersectsWith(this.containers[i].containerCache)) {
4794
4795
				// if we've already found a container and it's more "inner" than this, then continue
4796
				if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
4797
					continue;
4798
				}
4799
4800
				innermostContainer = this.containers[i];
4801
				innermostIndex = i;
4802
4803
			} else {
4804
				// container doesn't intersect. trigger "out" event if necessary
4805
				if(this.containers[i].containerCache.over) {
4806
					this.containers[i]._trigger("out", event, this._uiHash(this));
4807
					this.containers[i].containerCache.over = 0;
4808
				}
4809
			}
4810
4811
		}
4812
4813
		// if no intersecting containers found, return
4814
		if(!innermostContainer) {
4815
			return;
4816
		}
4817
4818
		// move the item into the container if it's not there already
4819
		if(this.containers.length === 1) {
4820
			if (!this.containers[innermostIndex].containerCache.over) {
4821
				this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4822
				this.containers[innermostIndex].containerCache.over = 1;
4823
			}
4824
		} else {
4825
4826
			//When entering a new container, we will find the item with the least distance and append our item near it
4827
			dist = 10000;
4828
			itemWithLeastDistance = null;
4829
			floating = innermostContainer.floating || isFloating(this.currentItem);
4830
			posProperty = floating ? "left" : "top";
4831
			sizeProperty = floating ? "width" : "height";
4832
			base = this.positionAbs[posProperty] + this.offset.click[posProperty];
4833
			for (j = this.items.length - 1; j >= 0; j--) {
4834
				if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
4835
					continue;
4836
				}
4837
				if(this.items[j].item[0] === this.currentItem[0]) {
4838
					continue;
4839
				}
4840
				if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) {
4841
					continue;
4842
				}
4843
				cur = this.items[j].item.offset()[posProperty];
4844
				nearBottom = false;
4845
				if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){
4846
					nearBottom = true;
4847
					cur += this.items[j][sizeProperty];
4848
				}
4849
4850
				if(Math.abs(cur - base) < dist) {
4851
					dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
4852
					this.direction = nearBottom ? "up": "down";
4853
				}
4854
			}
4855
4856
			//Check if dropOnEmpty is enabled
4857
			if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
4858
				return;
4859
			}
4860
4861
			if(this.currentContainer === this.containers[innermostIndex]) {
4862
				return;
4863
			}
4864
4865
			itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
4866
			this._trigger("change", event, this._uiHash());
4867
			this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
4868
			this.currentContainer = this.containers[innermostIndex];
4869
4870
			//Update the placeholder
4871
			this.options.placeholder.update(this.currentContainer, this.placeholder);
4872
4873
			this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
4874
			this.containers[innermostIndex].containerCache.over = 1;
4875
		}
4876
4877
4878
	},
4879
4880
	_createHelper: function(event) {
4881
4882
		var o = this.options,
4883
			helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
4884
4885
		//Add the helper to the DOM if that didn't happen already
4886
		if(!helper.parents("body").length) {
4887
			$(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
4888
		}
4889
4890
		if(helper[0] === this.currentItem[0]) {
4891
			this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
4892
		}
4893
4894
		if(!helper[0].style.width || o.forceHelperSize) {
4895
			helper.width(this.currentItem.width());
4896
		}
4897
		if(!helper[0].style.height || o.forceHelperSize) {
4898
			helper.height(this.currentItem.height());
4899
		}
4900
4901
		return helper;
4902
4903
	},
4904
4905
	_adjustOffsetFromHelper: function(obj) {
4906
		if (typeof obj === "string") {
4907
			obj = obj.split(" ");
4908
		}
4909
		if ($.isArray(obj)) {
4910
			obj = {left: +obj[0], top: +obj[1] || 0};
4911
		}
4912
		if ("left" in obj) {
4913
			this.offset.click.left = obj.left + this.margins.left;
4914
		}
4915
		if ("right" in obj) {
4916
			this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
4917
		}
4918
		if ("top" in obj) {
4919
			this.offset.click.top = obj.top + this.margins.top;
4920
		}
4921
		if ("bottom" in obj) {
4922
			this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
4923
		}
4924
	},
4925
4926
	_getParentOffset: function() {
4927
4928
4929
		//Get the offsetParent and cache its position
4930
		this.offsetParent = this.helper.offsetParent();
4931
		var po = this.offsetParent.offset();
4932
4933
		// This is a special case where we need to modify a offset calculated on start, since the following happened:
4934
		// 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
4935
		// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
4936
		//    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
4937
		if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
4938
			po.left += this.scrollParent.scrollLeft();
4939
			po.top += this.scrollParent.scrollTop();
4940
		}
4941
4942
		// This needs to be actually done for all browsers, since pageX/pageY includes this information
4943
		// with an ugly IE fix
4944
		if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
4945
			po = { top: 0, left: 0 };
4946
		}
4947
4948
		return {
4949
			top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
4950
			left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
4951
		};
4952
4953
	},
4954
4955
	_getRelativeOffset: function() {
4956
4957
		if(this.cssPosition === "relative") {
4958
			var p = this.currentItem.position();
4959
			return {
4960
				top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
4961
				left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
4962
			};
4963
		} else {
4964
			return { top: 0, left: 0 };
4965
		}
4966
4967
	},
4968
4969
	_cacheMargins: function() {
4970
		this.margins = {
4971
			left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
4972
			top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
4973
		};
4974
	},
4975
4976
	_cacheHelperProportions: function() {
4977
		this.helperProportions = {
4978
			width: this.helper.outerWidth(),
4979
			height: this.helper.outerHeight()
4980
		};
4981
	},
4982
4983
	_setContainment: function() {
4984
4985
		var ce, co, over,
4986
			o = this.options;
4987
		if(o.containment === "parent") {
4988
			o.containment = this.helper[0].parentNode;
4989
		}
4990
		if(o.containment === "document" || o.containment === "window") {
4991
			this.containment = [
4992
				0 - this.offset.relative.left - this.offset.parent.left,
4993
				0 - this.offset.relative.top - this.offset.parent.top,
4994
				$(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
4995
				($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
4996
			];
4997
		}
4998
4999
		if(!(/^(document|window|parent)$/).test(o.containment)) {
5000
			ce = $(o.containment)[0];
5001
			co = $(o.containment).offset();
5002
			over = ($(ce).css("overflow") !== "hidden");
5003
5004
			this.containment = [
5005
				co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
5006
				co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
5007
				co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
5008
				co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
5009
			];
5010
		}
5011
5012
	},
5013
5014
	_convertPositionTo: function(d, pos) {
5015
5016
		if(!pos) {
5017
			pos = this.position;
5018
		}
5019
		var mod = d === "absolute" ? 1 : -1,
5020
			scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
5021
			scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
5022
5023
		return {
5024
			top: (
5025
				pos.top	+																// The absolute mouse position
5026
				this.offset.relative.top * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
5027
				this.offset.parent.top * mod -											// The offsetParent's offset without borders (offset + border)
5028
				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
5029
			),
5030
			left: (
5031
				pos.left +																// The absolute mouse position
5032
				this.offset.relative.left * mod +										// Only for relative positioned nodes: Relative offset from element to offset parent
5033
				this.offset.parent.left * mod	-										// The offsetParent's offset without borders (offset + border)
5034
				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
5035
			)
5036
		};
5037
5038
	},
5039
5040
	_generatePosition: function(event) {
5041
5042
		var top, left,
5043
			o = this.options,
5044
			pageX = event.pageX,
5045
			pageY = event.pageY,
5046
			scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
5047
5048
		// This is another very weird special case that only happens for relative elements:
5049
		// 1. If the css position is relative
5050
		// 2. and the scroll parent is the document or similar to the offset parent
5051
		// we have to refresh the relative offset during the scroll so there are no jumps
5052
		if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
5053
			this.offset.relative = this._getRelativeOffset();
5054
		}
5055
5056
		/*
5057
		 * - Position constraining -
5058
		 * Constrain the position to a mix of grid, containment.
5059
		 */
5060
5061
		if(this.originalPosition) { //If we are not dragging yet, we won't check for options
5062
5063
			if(this.containment) {
5064
				if(event.pageX - this.offset.click.left < this.containment[0]) {
5065
					pageX = this.containment[0] + this.offset.click.left;
5066
				}
5067
				if(event.pageY - this.offset.click.top < this.containment[1]) {
5068
					pageY = this.containment[1] + this.offset.click.top;
5069
				}
5070
				if(event.pageX - this.offset.click.left > this.containment[2]) {
5071
					pageX = this.containment[2] + this.offset.click.left;
5072
				}
5073
				if(event.pageY - this.offset.click.top > this.containment[3]) {
5074
					pageY = this.containment[3] + this.offset.click.top;
5075
				}
5076
			}
5077
5078
			if(o.grid) {
5079
				top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
5080
				pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
5081
5082
				left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
5083
				pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
5084
			}
5085
5086
		}
5087
5088
		return {
5089
			top: (
5090
				pageY -																// The absolute mouse position
5091
				this.offset.click.top -													// Click offset (relative to the element)
5092
				this.offset.relative.top	-											// Only for relative positioned nodes: Relative offset from element to offset parent
5093
				this.offset.parent.top +												// The offsetParent's offset without borders (offset + border)
5094
				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
5095
			),
5096
			left: (
5097
				pageX -																// The absolute mouse position
5098
				this.offset.click.left -												// Click offset (relative to the element)
5099
				this.offset.relative.left	-											// Only for relative positioned nodes: Relative offset from element to offset parent
5100
				this.offset.parent.left +												// The offsetParent's offset without borders (offset + border)
5101
				( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
5102
			)
5103
		};
5104
5105
	},
5106
5107
	_rearrange: function(event, i, a, hardRefresh) {
5108
5109
		a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
5110
5111
		//Various things done here to improve the performance:
5112
		// 1. we create a setTimeout, that calls refreshPositions
5113
		// 2. on the instance, we have a counter variable, that get's higher after every append
5114
		// 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
5115
		// 4. this lets only the last addition to the timeout stack through
5116
		this.counter = this.counter ? ++this.counter : 1;
5117
		var counter = this.counter;
5118
5119
		this._delay(function() {
5120
			if(counter === this.counter) {
5121
				this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
5122
			}
5123
		});
5124
5125
	},
5126
5127
	_clear: function(event, noPropagation) {
5128
5129
		this.reverting = false;
5130
		// We delay all events that have to be triggered to after the point where the placeholder has been removed and
5131
		// everything else normalized again
5132
		var i,
5133
			delayedTriggers = [];
5134
5135
		// We first have to update the dom position of the actual currentItem
5136
		// Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
5137
		if(!this._noFinalSort && this.currentItem.parent().length) {
5138
			this.placeholder.before(this.currentItem);
5139
		}
5140
		this._noFinalSort = null;
5141
5142
		if(this.helper[0] === this.currentItem[0]) {
5143
			for(i in this._storedCSS) {
5144
				if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
5145
					this._storedCSS[i] = "";
5146
				}
5147
			}
5148
			this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
5149
		} else {
5150
			this.currentItem.show();
5151
		}
5152
5153
		if(this.fromOutside && !noPropagation) {
5154
			delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
5155
		}
5156
		if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
5157
			delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
5158
		}
5159
5160
		// Check if the items Container has Changed and trigger appropriate
5161
		// events.
5162
		if (this !== this.currentContainer) {
5163
			if(!noPropagation) {
5164
				delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
5165
				delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); };  }).call(this, this.currentContainer));
5166
				delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this));  }; }).call(this, this.currentContainer));
5167
			}
5168
		}
5169
5170
5171
		//Post events to containers
5172
		for (i = this.containers.length - 1; i >= 0; i--){
5173
			if(!noPropagation) {
5174
				delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
5175
			}
5176
			if(this.containers[i].containerCache.over) {
5177
				delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); };  }).call(this, this.containers[i]));
5178
				this.containers[i].containerCache.over = 0;
5179
			}
5180
		}
5181
5182
		//Do what was originally in plugins
5183
		if ( this.storedCursor ) {
5184
			this.document.find( "body" ).css( "cursor", this.storedCursor );
5185
			this.storedStylesheet.remove();
5186
		}
5187
		if(this._storedOpacity) {
5188
			this.helper.css("opacity", this._storedOpacity);
5189
		}
5190
		if(this._storedZIndex) {
5191
			this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
5192
		}
5193
5194
		this.dragging = false;
5195
		if(this.cancelHelperRemoval) {
5196
			if(!noPropagation) {
5197
				this._trigger("beforeStop", event, this._uiHash());
5198
				for (i=0; i < delayedTriggers.length; i++) {
5199
					delayedTriggers[i].call(this, event);
5200
				} //Trigger all delayed events
5201
				this._trigger("stop", event, this._uiHash());
5202
			}
5203
5204
			this.fromOutside = false;
5205
			return false;
5206
		}
5207
5208
		if(!noPropagation) {
5209
			this._trigger("beforeStop", event, this._uiHash());
5210
		}
5211
5212
		//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
5213
		this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
5214
5215
		if(this.helper[0] !== this.currentItem[0]) {
5216
			this.helper.remove();
5217
		}
5218
		this.helper = null;
5219
5220
		if(!noPropagation) {
5221
			for (i=0; i < delayedTriggers.length; i++) {
5222
				delayedTriggers[i].call(this, event);
5223
			} //Trigger all delayed events
5224
			this._trigger("stop", event, this._uiHash());
5225
		}
5226
5227
		this.fromOutside = false;
5228
		return true;
5229
5230
	},
5231
5232
	_trigger: function() {
5233
		if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
5234
			this.cancel();
5235
		}
5236
	},
5237
5238
	_uiHash: function(_inst) {
5239
		var inst = _inst || this;
5240
		return {
5241
			helper: inst.helper,
5242
			placeholder: inst.placeholder || $([]),
5243
			position: inst.position,
5244
			originalPosition: inst.originalPosition,
5245
			offset: inst.positionAbs,
5246
			item: inst.currentItem,
5247
			sender: _inst ? _inst.element : null
5248
		};
5249
	}
5250
5251
});
5252
5253
})(jQuery);
5254
(function( $, undefined ) {
5255
5256
// used to prevent race conditions with remote data sources
5257
var requestIndex = 0;
5258
5259
$.widget( "ui.autocomplete", {
5260
	version: "1.10.3",
5261
	defaultElement: "<input>",
5262
	options: {
5263
		appendTo: null,
5264
		autoFocus: false,
5265
		delay: 300,
5266
		minLength: 1,
5267
		position: {
5268
			my: "left top",
5269
			at: "left bottom",
5270
			collision: "none"
5271
		},
5272
		source: null,
5273
5274
		// callbacks
5275
		change: null,
5276
		close: null,
5277
		focus: null,
5278
		open: null,
5279
		response: null,
5280
		search: null,
5281
		select: null
5282
	},
5283
5284
	pending: 0,
5285
5286
	_create: function() {
5287
		// Some browsers only repeat keydown events, not keypress events,
5288
		// so we use the suppressKeyPress flag to determine if we've already
5289
		// handled the keydown event. #7269
5290
		// Unfortunately the code for & in keypress is the same as the up arrow,
5291
		// so we use the suppressKeyPressRepeat flag to avoid handling keypress
5292
		// events when we know the keydown event was used to modify the
5293
		// search term. #7799
5294
		var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
5295
			nodeName = this.element[0].nodeName.toLowerCase(),
5296
			isTextarea = nodeName === "textarea",
5297
			isInput = nodeName === "input";
5298
5299
		this.isMultiLine =
5300
			// Textareas are always multi-line
5301
			isTextarea ? true :
5302
			// Inputs are always single-line, even if inside a contentEditable element
5303
			// IE also treats inputs as contentEditable
5304
			isInput ? false :
5305
			// All other element types are determined by whether or not they're contentEditable
5306
			this.element.prop( "isContentEditable" );
5307
5308
		this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
5309
		this.isNewMenu = true;
5310
5311
		this.element
5312
			.addClass( "ui-autocomplete-input" )
5313
			.attr( "autocomplete", "off" );
5314
5315
		this._on( this.element, {
5316
			keydown: function( event ) {
5317
				/*jshint maxcomplexity:15*/
5318
				if ( this.element.prop( "readOnly" ) ) {
5319
					suppressKeyPress = true;
5320
					suppressInput = true;
5321
					suppressKeyPressRepeat = true;
5322
					return;
5323
				}
5324
5325
				suppressKeyPress = false;
5326
				suppressInput = false;
5327
				suppressKeyPressRepeat = false;
5328
				var keyCode = $.ui.keyCode;
5329
				switch( event.keyCode ) {
5330
				case keyCode.PAGE_UP:
5331
					suppressKeyPress = true;
5332
					this._move( "previousPage", event );
5333
					break;
5334
				case keyCode.PAGE_DOWN:
5335
					suppressKeyPress = true;
5336
					this._move( "nextPage", event );
5337
					break;
5338
				case keyCode.UP:
5339
					suppressKeyPress = true;
5340
					this._keyEvent( "previous", event );
5341
					break;
5342
				case keyCode.DOWN:
5343
					suppressKeyPress = true;
5344
					this._keyEvent( "next", event );
5345
					break;
5346
				case keyCode.ENTER:
5347
				case keyCode.NUMPAD_ENTER:
5348
					// when menu is open and has focus
5349
					if ( this.menu.active ) {
5350
						// #6055 - Opera still allows the keypress to occur
5351
						// which causes forms to submit
5352
						suppressKeyPress = true;
5353
						event.preventDefault();
5354
						this.menu.select( event );
5355
					}
5356
					break;
5357
				case keyCode.TAB:
5358
					if ( this.menu.active ) {
5359
						this.menu.select( event );
5360
					}
5361
					break;
5362
				case keyCode.ESCAPE:
5363
					if ( this.menu.element.is( ":visible" ) ) {
5364
						this._value( this.term );
5365
						this.close( event );
5366
						// Different browsers have different default behavior for escape
5367
						// Single press can mean undo or clear
5368
						// Double press in IE means clear the whole form
5369
						event.preventDefault();
5370
					}
5371
					break;
5372
				default:
5373
					suppressKeyPressRepeat = true;
5374
					// search timeout should be triggered before the input value is changed
5375
					this._searchTimeout( event );
5376
					break;
5377
				}
5378
			},
5379
			keypress: function( event ) {
5380
				if ( suppressKeyPress ) {
5381
					suppressKeyPress = false;
5382
					if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5383
						event.preventDefault();
5384
					}
5385
					return;
5386
				}
5387
				if ( suppressKeyPressRepeat ) {
5388
					return;
5389
				}
5390
5391
				// replicate some key handlers to allow them to repeat in Firefox and Opera
5392
				var keyCode = $.ui.keyCode;
5393
				switch( event.keyCode ) {
5394
				case keyCode.PAGE_UP:
5395
					this._move( "previousPage", event );
5396
					break;
5397
				case keyCode.PAGE_DOWN:
5398
					this._move( "nextPage", event );
5399
					break;
5400
				case keyCode.UP:
5401
					this._keyEvent( "previous", event );
5402
					break;
5403
				case keyCode.DOWN:
5404
					this._keyEvent( "next", event );
5405
					break;
5406
				}
5407
			},
5408
			input: function( event ) {
5409
				if ( suppressInput ) {
5410
					suppressInput = false;
5411
					event.preventDefault();
5412
					return;
5413
				}
5414
				this._searchTimeout( event );
5415
			},
5416
			focus: function() {
5417
				this.selectedItem = null;
5418
				this.previous = this._value();
5419
			},
5420
			blur: function( event ) {
5421
				if ( this.cancelBlur ) {
5422
					delete this.cancelBlur;
5423
					return;
5424
				}
5425
5426
				clearTimeout( this.searching );
5427
				this.close( event );
5428
				this._change( event );
5429
			}
5430
		});
5431
5432
		this._initSource();
5433
		this.menu = $( "<ul>" )
5434
			.addClass( "ui-autocomplete ui-front" )
5435
			.appendTo( this._appendTo() )
5436
			.menu({
5437
				// disable ARIA support, the live region takes care of that
5438
				role: null
5439
			})
5440
			.hide()
5441
			.data( "ui-menu" );
5442
5443
		this._on( this.menu.element, {
5444
			mousedown: function( event ) {
5445
				// prevent moving focus out of the text field
5446
				event.preventDefault();
5447
5448
				// IE doesn't prevent moving focus even with event.preventDefault()
5449
				// so we set a flag to know when we should ignore the blur event
5450
				this.cancelBlur = true;
5451
				this._delay(function() {
5452
					delete this.cancelBlur;
5453
				});
5454
5455
				// clicking on the scrollbar causes focus to shift to the body
5456
				// but we can't detect a mouseup or a click immediately afterward
5457
				// so we have to track the next mousedown and close the menu if
5458
				// the user clicks somewhere outside of the autocomplete
5459
				var menuElement = this.menu.element[ 0 ];
5460
				if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
5461
					this._delay(function() {
5462
						var that = this;
5463
						this.document.one( "mousedown", function( event ) {
5464
							if ( event.target !== that.element[ 0 ] &&
5465
									event.target !== menuElement &&
5466
									!$.contains( menuElement, event.target ) ) {
5467
								that.close();
5468
							}
5469
						});
5470
					});
5471
				}
5472
			},
5473
			menufocus: function( event, ui ) {
5474
				// support: Firefox
5475
				// Prevent accidental activation of menu items in Firefox (#7024 #9118)
5476
				if ( this.isNewMenu ) {
5477
					this.isNewMenu = false;
5478
					if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
5479
						this.menu.blur();
5480
5481
						this.document.one( "mousemove", function() {
5482
							$( event.target ).trigger( event.originalEvent );
5483
						});
5484
5485
						return;
5486
					}
5487
				}
5488
5489
				var item = ui.item.data( "ui-autocomplete-item" );
5490
				if ( false !== this._trigger( "focus", event, { item: item } ) ) {
5491
					// use value to match what will end up in the input, if it was a key event
5492
					if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
5493
						this._value( item.value );
5494
					}
5495
				} else {
5496
					// Normally the input is populated with the item's value as the
5497
					// menu is navigated, causing screen readers to notice a change and
5498
					// announce the item. Since the focus event was canceled, this doesn't
5499
					// happen, so we update the live region so that screen readers can
5500
					// still notice the change and announce it.
5501
					this.liveRegion.text( item.value );
5502
				}
5503
			},
5504
			menuselect: function( event, ui ) {
5505
				var item = ui.item.data( "ui-autocomplete-item" ),
5506
					previous = this.previous;
5507
5508
				// only trigger when focus was lost (click on menu)
5509
				if ( this.element[0] !== this.document[0].activeElement ) {
5510
					this.element.focus();
5511
					this.previous = previous;
5512
					// #6109 - IE triggers two focus events and the second
5513
					// is asynchronous, so we need to reset the previous
5514
					// term synchronously and asynchronously :-(
5515
					this._delay(function() {
5516
						this.previous = previous;
5517
						this.selectedItem = item;
5518
					});
5519
				}
5520
5521
				if ( false !== this._trigger( "select", event, { item: item } ) ) {
5522
					this._value( item.value );
5523
				}
5524
				// reset the term after the select event
5525
				// this allows custom select handling to work properly
5526
				this.term = this._value();
5527
5528
				this.close( event );
5529
				this.selectedItem = item;
5530
			}
5531
		});
5532
5533
		this.liveRegion = $( "<span>", {
5534
				role: "status",
5535
				"aria-live": "polite"
5536
			})
5537
			.addClass( "ui-helper-hidden-accessible" )
5538
			.insertBefore( this.element );
5539
5540
		// turning off autocomplete prevents the browser from remembering the
5541
		// value when navigating through history, so we re-enable autocomplete
5542
		// if the page is unloaded before the widget is destroyed. #7790
5543
		this._on( this.window, {
5544
			beforeunload: function() {
5545
				this.element.removeAttr( "autocomplete" );
5546
			}
5547
		});
5548
	},
5549
5550
	_destroy: function() {
5551
		clearTimeout( this.searching );
5552
		this.element
5553
			.removeClass( "ui-autocomplete-input" )
5554
			.removeAttr( "autocomplete" );
5555
		this.menu.element.remove();
5556
		this.liveRegion.remove();
5557
	},
5558
5559
	_setOption: function( key, value ) {
5560
		this._super( key, value );
5561
		if ( key === "source" ) {
5562
			this._initSource();
5563
		}
5564
		if ( key === "appendTo" ) {
5565
			this.menu.element.appendTo( this._appendTo() );
5566
		}
5567
		if ( key === "disabled" && value && this.xhr ) {
5568
			this.xhr.abort();
5569
		}
5570
	},
5571
5572
	_appendTo: function() {
5573
		var element = this.options.appendTo;
5574
5575
		if ( element ) {
5576
			element = element.jquery || element.nodeType ?
5577
				$( element ) :
5578
				this.document.find( element ).eq( 0 );
5579
		}
5580
5581
		if ( !element ) {
5582
			element = this.element.closest( ".ui-front" );
5583
		}
5584
5585
		if ( !element.length ) {
5586
			element = this.document[0].body;
5587
		}
5588
5589
		return element;
5590
	},
5591
5592
	_initSource: function() {
5593
		var array, url,
5594
			that = this;
5595
		if ( $.isArray(this.options.source) ) {
5596
			array = this.options.source;
5597
			this.source = function( request, response ) {
5598
				response( $.ui.autocomplete.filter( array, request.term ) );
5599
			};
5600
		} else if ( typeof this.options.source === "string" ) {
5601
			url = this.options.source;
5602
			this.source = function( request, response ) {
5603
				if ( that.xhr ) {
5604
					that.xhr.abort();
5605
				}
5606
				that.xhr = $.ajax({
5607
					url: url,
5608
					data: request,
5609
					dataType: "json",
5610
					success: function( data ) {
5611
						response( data );
5612
					},
5613
					error: function() {
5614
						response( [] );
5615
					}
5616
				});
5617
			};
5618
		} else {
5619
			this.source = this.options.source;
5620
		}
5621
	},
5622
5623
	_searchTimeout: function( event ) {
5624
		clearTimeout( this.searching );
5625
		this.searching = this._delay(function() {
5626
			// only search if the value has changed
5627
			if ( this.term !== this._value() ) {
5628
				this.selectedItem = null;
5629
				this.search( null, event );
5630
			}
5631
		}, this.options.delay );
5632
	},
5633
5634
	search: function( value, event ) {
5635
		value = value != null ? value : this._value();
5636
5637
		// always save the actual value, not the one passed as an argument
5638
		this.term = this._value();
5639
5640
		if ( value.length < this.options.minLength ) {
5641
			return this.close( event );
5642
		}
5643
5644
		if ( this._trigger( "search", event ) === false ) {
5645
			return;
5646
		}
5647
5648
		return this._search( value );
5649
	},
5650
5651
	_search: function( value ) {
5652
		this.pending++;
5653
		this.element.addClass( "ui-autocomplete-loading" );
5654
		this.cancelSearch = false;
5655
5656
		this.source( { term: value }, this._response() );
5657
	},
5658
5659
	_response: function() {
5660
		var that = this,
5661
			index = ++requestIndex;
5662
5663
		return function( content ) {
5664
			if ( index === requestIndex ) {
5665
				that.__response( content );
5666
			}
5667
5668
			that.pending--;
5669
			if ( !that.pending ) {
5670
				that.element.removeClass( "ui-autocomplete-loading" );
5671
			}
5672
		};
5673
	},
5674
5675
	__response: function( content ) {
5676
		if ( content ) {
5677
			content = this._normalize( content );
5678
		}
5679
		this._trigger( "response", null, { content: content } );
5680
		if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
5681
			this._suggest( content );
5682
			this._trigger( "open" );
5683
		} else {
5684
			// use ._close() instead of .close() so we don't cancel future searches
5685
			this._close();
5686
		}
5687
	},
5688
5689
	close: function( event ) {
5690
		this.cancelSearch = true;
5691
		this._close( event );
5692
	},
5693
5694
	_close: function( event ) {
5695
		if ( this.menu.element.is( ":visible" ) ) {
5696
			this.menu.element.hide();
5697
			this.menu.blur();
5698
			this.isNewMenu = true;
5699
			this._trigger( "close", event );
5700
		}
5701
	},
5702
5703
	_change: function( event ) {
5704
		if ( this.previous !== this._value() ) {
5705
			this._trigger( "change", event, { item: this.selectedItem } );
5706
		}
5707
	},
5708
5709
	_normalize: function( items ) {
5710
		// assume all items have the right format when the first item is complete
5711
		if ( items.length && items[0].label && items[0].value ) {
5712
			return items;
5713
		}
5714
		return $.map( items, function( item ) {
5715
			if ( typeof item === "string" ) {
5716
				return {
5717
					label: item,
5718
					value: item
5719
				};
5720
			}
5721
			return $.extend({
5722
				label: item.label || item.value,
5723
				value: item.value || item.label
5724
			}, item );
5725
		});
5726
	},
5727
5728
	_suggest: function( items ) {
5729
		var ul = this.menu.element.empty();
5730
		this._renderMenu( ul, items );
5731
		this.isNewMenu = true;
5732
		this.menu.refresh();
5733
5734
		// size and position menu
5735
		ul.show();
5736
		this._resizeMenu();
5737
		ul.position( $.extend({
5738
			of: this.element
5739
		}, this.options.position ));
5740
5741
		if ( this.options.autoFocus ) {
5742
			this.menu.next();
5743
		}
5744
	},
5745
5746
	_resizeMenu: function() {
5747
		var ul = this.menu.element;
5748
		ul.outerWidth( Math.max(
5749
			// Firefox wraps long text (possibly a rounding bug)
5750
			// so we add 1px to avoid the wrapping (#7513)
5751
			ul.width( "" ).outerWidth() + 1,
5752
			this.element.outerWidth()
5753
		) );
5754
	},
5755
5756
	_renderMenu: function( ul, items ) {
5757
		var that = this;
5758
		$.each( items, function( index, item ) {
5759
			that._renderItemData( ul, item );
5760
		});
5761
	},
5762
5763
	_renderItemData: function( ul, item ) {
5764
		return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
5765
	},
5766
5767
	_renderItem: function( ul, item ) {
5768
		return $( "<li>" )
5769
			.append( $( "<a>" ).text( item.label ) )
5770
			.appendTo( ul );
5771
	},
5772
5773
	_move: function( direction, event ) {
5774
		if ( !this.menu.element.is( ":visible" ) ) {
5775
			this.search( null, event );
5776
			return;
5777
		}
5778
		if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
5779
				this.menu.isLastItem() && /^next/.test( direction ) ) {
5780
			this._value( this.term );
5781
			this.menu.blur();
5782
			return;
5783
		}
5784
		this.menu[ direction ]( event );
5785
	},
5786
5787
	widget: function() {
5788
		return this.menu.element;
5789
	},
5790
5791
	_value: function() {
5792
		return this.valueMethod.apply( this.element, arguments );
5793
	},
5794
5795
	_keyEvent: function( keyEvent, event ) {
5796
		if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
5797
			this._move( keyEvent, event );
5798
5799
			// prevents moving cursor to beginning/end of the text field in some browsers
5800
			event.preventDefault();
5801
		}
5802
	}
5803
});
5804
5805
$.extend( $.ui.autocomplete, {
5806
	escapeRegex: function( value ) {
5807
		return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
5808
	},
5809
	filter: function(array, term) {
5810
		var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
5811
		return $.grep( array, function(value) {
5812
			return matcher.test( value.label || value.value || value );
5813
		});
5814
	}
5815
});
5816
5817
5818
// live region extension, adding a `messages` option
5819
// NOTE: This is an experimental API. We are still investigating
5820
// a full solution for string manipulation and internationalization.
5821
$.widget( "ui.autocomplete", $.ui.autocomplete, {
5822
	options: {
5823
		messages: {
5824
			noResults: "No search results.",
5825
			results: function( amount ) {
5826
				return amount + ( amount > 1 ? " results are" : " result is" ) +
5827
					" available, use up and down arrow keys to navigate.";
5828
			}
5829
		}
5830
	},
5831
5832
	__response: function( content ) {
5833
		var message;
5834
		this._superApply( arguments );
5835
		if ( this.options.disabled || this.cancelSearch ) {
5836
			return;
5837
		}
5838
		if ( content && content.length ) {
5839
			message = this.options.messages.results( content.length );
5840
		} else {
5841
			message = this.options.messages.noResults;
5842
		}
5843
		this.liveRegion.text( message );
5844
	}
5845
});
5846
5847
}( jQuery ));
5848
(function( $, undefined ) {
5849
5850
$.widget( "ui.menu", {
5851
	version: "1.10.3",
5852
	defaultElement: "<ul>",
5853
	delay: 300,
5854
	options: {
5855
		icons: {
5856
			submenu: "ui-icon-carat-1-e"
5857
		},
5858
		menus: "ul",
5859
		position: {
5860
			my: "left top",
5861
			at: "right top"
5862
		},
5863
		role: "menu",
5864
5865
		// callbacks
5866
		blur: null,
5867
		focus: null,
5868
		select: null
5869
	},
5870
5871
	_create: function() {
5872
		this.activeMenu = this.element;
5873
		// flag used to prevent firing of the click handler
5874
		// as the event bubbles up through nested menus
5875
		this.mouseHandled = false;
5876
		this.element
5877
			.uniqueId()
5878
			.addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
5879
			.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
5880
			.attr({
5881
				role: this.options.role,
5882
				tabIndex: 0
5883
			})
5884
			// need to catch all clicks on disabled menu
5885
			// not possible through _on
5886
			.bind( "click" + this.eventNamespace, $.proxy(function( event ) {
5887
				if ( this.options.disabled ) {
5888
					event.preventDefault();
5889
				}
5890
			}, this ));
5891
5892
		if ( this.options.disabled ) {
5893
			this.element
5894
				.addClass( "ui-state-disabled" )
5895
				.attr( "aria-disabled", "true" );
5896
		}
5897
5898
		this._on({
5899
			// Prevent focus from sticking to links inside menu after clicking
5900
			// them (focus should always stay on UL during navigation).
5901
			"mousedown .ui-menu-item > a": function( event ) {
5902
				event.preventDefault();
5903
			},
5904
			"click .ui-state-disabled > a": function( event ) {
5905
				event.preventDefault();
5906
			},
5907
			"click .ui-menu-item:has(a)": function( event ) {
5908
				var target = $( event.target ).closest( ".ui-menu-item" );
5909
				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
5910
					this.mouseHandled = true;
5911
5912
					this.select( event );
5913
					// Open submenu on click
5914
					if ( target.has( ".ui-menu" ).length ) {
5915
						this.expand( event );
5916
					} else if ( !this.element.is( ":focus" ) ) {
5917
						// Redirect focus to the menu
5918
						this.element.trigger( "focus", [ true ] );
5919
5920
						// If the active item is on the top level, let it stay active.
5921
						// Otherwise, blur the active item since it is no longer visible.
5922
						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
5923
							clearTimeout( this.timer );
5924
						}
5925
					}
5926
				}
5927
			},
5928
			"mouseenter .ui-menu-item": function( event ) {
5929
				var target = $( event.currentTarget );
5930
				// Remove ui-state-active class from siblings of the newly focused menu item
5931
				// to avoid a jump caused by adjacent elements both having a class with a border
5932
				target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
5933
				this.focus( event, target );
5934
			},
5935
			mouseleave: "collapseAll",
5936
			"mouseleave .ui-menu": "collapseAll",
5937
			focus: function( event, keepActiveItem ) {
5938
				// If there's already an active item, keep it active
5939
				// If not, activate the first item
5940
				var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
5941
5942
				if ( !keepActiveItem ) {
5943
					this.focus( event, item );
5944
				}
5945
			},
5946
			blur: function( event ) {
5947
				this._delay(function() {
5948
					if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
5949
						this.collapseAll( event );
5950
					}
5951
				});
5952
			},
5953
			keydown: "_keydown"
5954
		});
5955
5956
		this.refresh();
5957
5958
		// Clicks outside of a menu collapse any open menus
5959
		this._on( this.document, {
5960
			click: function( event ) {
5961
				if ( !$( event.target ).closest( ".ui-menu" ).length ) {
5962
					this.collapseAll( event );
5963
				}
5964
5965
				// Reset the mouseHandled flag
5966
				this.mouseHandled = false;
5967
			}
5968
		});
5969
	},
5970
5971
	_destroy: function() {
5972
		// Destroy (sub)menus
5973
		this.element
5974
			.removeAttr( "aria-activedescendant" )
5975
			.find( ".ui-menu" ).addBack()
5976
				.removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
5977
				.removeAttr( "role" )
5978
				.removeAttr( "tabIndex" )
5979
				.removeAttr( "aria-labelledby" )
5980
				.removeAttr( "aria-expanded" )
5981
				.removeAttr( "aria-hidden" )
5982
				.removeAttr( "aria-disabled" )
5983
				.removeUniqueId()
5984
				.show();
5985
5986
		// Destroy menu items
5987
		this.element.find( ".ui-menu-item" )
5988
			.removeClass( "ui-menu-item" )
5989
			.removeAttr( "role" )
5990
			.removeAttr( "aria-disabled" )
5991
			.children( "a" )
5992
				.removeUniqueId()
5993
				.removeClass( "ui-corner-all ui-state-hover" )
5994
				.removeAttr( "tabIndex" )
5995
				.removeAttr( "role" )
5996
				.removeAttr( "aria-haspopup" )
5997
				.children().each( function() {
5998
					var elem = $( this );
5999
					if ( elem.data( "ui-menu-submenu-carat" ) ) {
6000
						elem.remove();
6001
					}
6002
				});
6003
6004
		// Destroy menu dividers
6005
		this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
6006
	},
6007
6008
	_keydown: function( event ) {
6009
		/*jshint maxcomplexity:20*/
6010
		var match, prev, character, skip, regex,
6011
			preventDefault = true;
6012
6013
		function escape( value ) {
6014
			return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
6015
		}
6016
6017
		switch ( event.keyCode ) {
6018
		case $.ui.keyCode.PAGE_UP:
6019
			this.previousPage( event );
6020
			break;
6021
		case $.ui.keyCode.PAGE_DOWN:
6022
			this.nextPage( event );
6023
			break;
6024
		case $.ui.keyCode.HOME:
6025
			this._move( "first", "first", event );
6026
			break;
6027
		case $.ui.keyCode.END:
6028
			this._move( "last", "last", event );
6029
			break;
6030
		case $.ui.keyCode.UP:
6031
			this.previous( event );
6032
			break;
6033
		case $.ui.keyCode.DOWN:
6034
			this.next( event );
6035
			break;
6036
		case $.ui.keyCode.LEFT:
6037
			this.collapse( event );
6038
			break;
6039
		case $.ui.keyCode.RIGHT:
6040
			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
6041
				this.expand( event );
6042
			}
6043
			break;
6044
		case $.ui.keyCode.ENTER:
6045
		case $.ui.keyCode.SPACE:
6046
			this._activate( event );
6047
			break;
6048
		case $.ui.keyCode.ESCAPE:
6049
			this.collapse( event );
6050
			break;
6051
		default:
6052
			preventDefault = false;
6053
			prev = this.previousFilter || "";
6054
			character = String.fromCharCode( event.keyCode );
6055
			skip = false;
6056
6057
			clearTimeout( this.filterTimer );
6058
6059
			if ( character === prev ) {
6060
				skip = true;
6061
			} else {
6062
				character = prev + character;
6063
			}
6064
6065
			regex = new RegExp( "^" + escape( character ), "i" );
6066
			match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
6067
				return regex.test( $( this ).children( "a" ).text() );
6068
			});
6069
			match = skip && match.index( this.active.next() ) !== -1 ?
6070
				this.active.nextAll( ".ui-menu-item" ) :
6071
				match;
6072
6073
			// If no matches on the current filter, reset to the last character pressed
6074
			// to move down the menu to the first item that starts with that character
6075
			if ( !match.length ) {
6076
				character = String.fromCharCode( event.keyCode );
6077
				regex = new RegExp( "^" + escape( character ), "i" );
6078
				match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
6079
					return regex.test( $( this ).children( "a" ).text() );
6080
				});
6081
			}
6082
6083
			if ( match.length ) {
6084
				this.focus( event, match );
6085
				if ( match.length > 1 ) {
6086
					this.previousFilter = character;
6087
					this.filterTimer = this._delay(function() {
6088
						delete this.previousFilter;
6089
					}, 1000 );
6090
				} else {
6091
					delete this.previousFilter;
6092
				}
6093
			} else {
6094
				delete this.previousFilter;
6095
			}
6096
		}
6097
6098
		if ( preventDefault ) {
6099
			event.preventDefault();
6100
		}
6101
	},
6102
6103
	_activate: function( event ) {
6104
		if ( !this.active.is( ".ui-state-disabled" ) ) {
6105
			if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
6106
				this.expand( event );
6107
			} else {
6108
				this.select( event );
6109
			}
6110
		}
6111
	},
6112
6113
	refresh: function() {
6114
		var menus,
6115
			icon = this.options.icons.submenu,
6116
			submenus = this.element.find( this.options.menus );
6117
6118
		// Initialize nested menus
6119
		submenus.filter( ":not(.ui-menu)" )
6120
			.addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
6121
			.hide()
6122
			.attr({
6123
				role: this.options.role,
6124
				"aria-hidden": "true",
6125
				"aria-expanded": "false"
6126
			})
6127
			.each(function() {
6128
				var menu = $( this ),
6129
					item = menu.prev( "a" ),
6130
					submenuCarat = $( "<span>" )
6131
						.addClass( "ui-menu-icon ui-icon " + icon )
6132
						.data( "ui-menu-submenu-carat", true );
6133
6134
				item
6135
					.attr( "aria-haspopup", "true" )
6136
					.prepend( submenuCarat );
6137
				menu.attr( "aria-labelledby", item.attr( "id" ) );
6138
			});
6139
6140
		menus = submenus.add( this.element );
6141
6142
		// Don't refresh list items that are already adapted
6143
		menus.children( ":not(.ui-menu-item):has(a)" )
6144
			.addClass( "ui-menu-item" )
6145
			.attr( "role", "presentation" )
6146
			.children( "a" )
6147
				.uniqueId()
6148
				.addClass( "ui-corner-all" )
6149
				.attr({
6150
					tabIndex: -1,
6151
					role: this._itemRole()
6152
				});
6153
6154
		// Initialize unlinked menu-items containing spaces and/or dashes only as dividers
6155
		menus.children( ":not(.ui-menu-item)" ).each(function() {
6156
			var item = $( this );
6157
			// hyphen, em dash, en dash
6158
			if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) {
6159
				item.addClass( "ui-widget-content ui-menu-divider" );
6160
			}
6161
		});
6162
6163
		// Add aria-disabled attribute to any disabled menu item
6164
		menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
6165
6166
		// If the active item has been removed, blur the menu
6167
		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
6168
			this.blur();
6169
		}
6170
	},
6171
6172
	_itemRole: function() {
6173
		return {
6174
			menu: "menuitem",
6175
			listbox: "option"
6176
		}[ this.options.role ];
6177
	},
6178
6179
	_setOption: function( key, value ) {
6180
		if ( key === "icons" ) {
6181
			this.element.find( ".ui-menu-icon" )
6182
				.removeClass( this.options.icons.submenu )
6183
				.addClass( value.submenu );
6184
		}
6185
		this._super( key, value );
6186
	},
6187
6188
	focus: function( event, item ) {
6189
		var nested, focused;
6190
		this.blur( event, event && event.type === "focus" );
6191
6192
		this._scrollIntoView( item );
6193
6194
		this.active = item.first();
6195
		focused = this.active.children( "a" ).addClass( "ui-state-focus" );
6196
		// Only update aria-activedescendant if there's a role
6197
		// otherwise we assume focus is managed elsewhere
6198
		if ( this.options.role ) {
6199
			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
6200
		}
6201
6202
		// Highlight active parent menu item, if any
6203
		this.active
6204
			.parent()
6205
			.closest( ".ui-menu-item" )
6206
			.children( "a:first" )
6207
			.addClass( "ui-state-active" );
6208
6209
		if ( event && event.type === "keydown" ) {
6210
			this._close();
6211
		} else {
6212
			this.timer = this._delay(function() {
6213
				this._close();
6214
			}, this.delay );
6215
		}
6216
6217
		nested = item.children( ".ui-menu" );
6218
		if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
6219
			this._startOpening(nested);
6220
		}
6221
		this.activeMenu = item.parent();
6222
6223
		this._trigger( "focus", event, { item: item } );
6224
	},
6225
6226
	_scrollIntoView: function( item ) {
6227
		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
6228
		if ( this._hasScroll() ) {
6229
			borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
6230
			paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
6231
			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
6232
			scroll = this.activeMenu.scrollTop();
6233
			elementHeight = this.activeMenu.height();
6234
			itemHeight = item.height();
6235
6236
			if ( offset < 0 ) {
6237
				this.activeMenu.scrollTop( scroll + offset );
6238
			} else if ( offset + itemHeight > elementHeight ) {
6239
				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
6240
			}
6241
		}
6242
	},
6243
6244
	blur: function( event, fromFocus ) {
6245
		if ( !fromFocus ) {
6246
			clearTimeout( this.timer );
6247
		}
6248
6249
		if ( !this.active ) {
6250
			return;
6251
		}
6252
6253
		this.active.children( "a" ).removeClass( "ui-state-focus" );
6254
		this.active = null;
6255
6256
		this._trigger( "blur", event, { item: this.active } );
6257
	},
6258
6259
	_startOpening: function( submenu ) {
6260
		clearTimeout( this.timer );
6261
6262
		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
6263
		// shift in the submenu position when mousing over the carat icon
6264
		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
6265
			return;
6266
		}
6267
6268
		this.timer = this._delay(function() {
6269
			this._close();
6270
			this._open( submenu );
6271
		}, this.delay );
6272
	},
6273
6274
	_open: function( submenu ) {
6275
		var position = $.extend({
6276
			of: this.active
6277
		}, this.options.position );
6278
6279
		clearTimeout( this.timer );
6280
		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
6281
			.hide()
6282
			.attr( "aria-hidden", "true" );
6283
6284
		submenu
6285
			.show()
6286
			.removeAttr( "aria-hidden" )
6287
			.attr( "aria-expanded", "true" )
6288
			.position( position );
6289
	},
6290
6291
	collapseAll: function( event, all ) {
6292
		clearTimeout( this.timer );
6293
		this.timer = this._delay(function() {
6294
			// If we were passed an event, look for the submenu that contains the event
6295
			var currentMenu = all ? this.element :
6296
				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
6297
6298
			// If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
6299
			if ( !currentMenu.length ) {
6300
				currentMenu = this.element;
6301
			}
6302
6303
			this._close( currentMenu );
6304
6305
			this.blur( event );
6306
			this.activeMenu = currentMenu;
6307
		}, this.delay );
6308
	},
6309
6310
	// With no arguments, closes the currently active menu - if nothing is active
6311
	// it closes all menus.  If passed an argument, it will search for menus BELOW
6312
	_close: function( startMenu ) {
6313
		if ( !startMenu ) {
6314
			startMenu = this.active ? this.active.parent() : this.element;
6315
		}
6316
6317
		startMenu
6318
			.find( ".ui-menu" )
6319
				.hide()
6320
				.attr( "aria-hidden", "true" )
6321
				.attr( "aria-expanded", "false" )
6322
			.end()
6323
			.find( "a.ui-state-active" )
6324
				.removeClass( "ui-state-active" );
6325
	},
6326
6327
	collapse: function( event ) {
6328
		var newItem = this.active &&
6329
			this.active.parent().closest( ".ui-menu-item", this.element );
6330
		if ( newItem && newItem.length ) {
6331
			this._close();
6332
			this.focus( event, newItem );
6333
		}
6334
	},
6335
6336
	expand: function( event ) {
6337
		var newItem = this.active &&
6338
			this.active
6339
				.children( ".ui-menu " )
6340
				.children( ".ui-menu-item" )
6341
				.first();
6342
6343
		if ( newItem && newItem.length ) {
6344
			this._open( newItem.parent() );
6345
6346
			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
6347
			this._delay(function() {
6348
				this.focus( event, newItem );
6349
			});
6350
		}
6351
	},
6352
6353
	next: function( event ) {
6354
		this._move( "next", "first", event );
6355
	},
6356
6357
	previous: function( event ) {
6358
		this._move( "prev", "last", event );
6359
	},
6360
6361
	isFirstItem: function() {
6362
		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
6363
	},
6364
6365
	isLastItem: function() {
6366
		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
6367
	},
6368
6369
	_move: function( direction, filter, event ) {
6370
		var next;
6371
		if ( this.active ) {
6372
			if ( direction === "first" || direction === "last" ) {
6373
				next = this.active
6374
					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
6375
					.eq( -1 );
6376
			} else {
6377
				next = this.active
6378
					[ direction + "All" ]( ".ui-menu-item" )
6379
					.eq( 0 );
6380
			}
6381
		}
6382
		if ( !next || !next.length || !this.active ) {
6383
			next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
6384
		}
6385
6386
		this.focus( event, next );
6387
	},
6388
6389
	nextPage: function( event ) {
6390
		var item, base, height;
6391
6392
		if ( !this.active ) {
6393
			this.next( event );
6394
			return;
6395
		}
6396
		if ( this.isLastItem() ) {
6397
			return;
6398
		}
6399
		if ( this._hasScroll() ) {
6400
			base = this.active.offset().top;
6401
			height = this.element.height();
6402
			this.active.nextAll( ".ui-menu-item" ).each(function() {
6403
				item = $( this );
6404
				return item.offset().top - base - height < 0;
6405
			});
6406
6407
			this.focus( event, item );
6408
		} else {
6409
			this.focus( event, this.activeMenu.children( ".ui-menu-item" )
6410
				[ !this.active ? "first" : "last" ]() );
6411
		}
6412
	},
6413
6414
	previousPage: function( event ) {
6415
		var item, base, height;
6416
		if ( !this.active ) {
6417
			this.next( event );
6418
			return;
6419
		}
6420
		if ( this.isFirstItem() ) {
6421
			return;
6422
		}
6423
		if ( this._hasScroll() ) {
6424
			base = this.active.offset().top;
6425
			height = this.element.height();
6426
			this.active.prevAll( ".ui-menu-item" ).each(function() {
6427
				item = $( this );
6428
				return item.offset().top - base + height > 0;
6429
			});
6430
6431
			this.focus( event, item );
6432
		} else {
6433
			this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
6434
		}
6435
	},
6436
6437
	_hasScroll: function() {
6438
		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
6439
	},
6440
6441
	select: function( event ) {
6442
		// TODO: It should never be possible to not have an active item at this
6443
		// point, but the tests don't trigger mouseenter before click.
6444
		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
6445
		var ui = { item: this.active };
6446
		if ( !this.active.has( ".ui-menu" ).length ) {
6447
			this.collapseAll( event, true );
6448
		}
6449
		this._trigger( "select", event, ui );
6450
	}
6451
});
6452
6453
}( jQuery ));
6454